2011-01-22 18 views
10

Eliminé algunos html a través de xpath, que luego convertí en un etree. Algo similar a esto:lxml.etree, element.text no devuelve el texto completo de un elemento

<td> text1 <a> link </a> text2 </td> 

pero cuando llamo element.text, solo me dan Text1 (Debe estar allí, cuando compruebo mi consulta en FireBug, el texto de los elementos se destaca, tanto en el texto antes y después de los elementos de anclaje integrados ...

+0

Esta es una forma de hacerlo (fragmento de código de mi pequeño procesador de raspado de python). Me pregunto si esto es un error lxml? – user522034

+0

He aquí el fragmento de código: – user522034

+0

si element.tag == "td": \t \t \t \t hijos = element.getchildren() \t \t \t \t si len (niños)> 0: \t \t \t \t \t topic = (+ element.text niños [0] .tail) \t \t \t \t otra cosa: \t \t \t \t \t topic = eleme Nuevo Testamento.texto \t \t \t \t print ("\ tTópico: \ t \ t% s"% tema) – user522034

Respuesta

15

uso element.xpath("string()") o lxml.etree.tostring(element, method="text") -.. ver the documentation

+0

toString (elemento, método = "texto") casi funciona, pero también devuelve el texto del elemento ancla incrustado, que no quiero – user522034

+0

element.text + child.tail funciona, pero me gustaría que element.text funcionara como yo quiero :) – user522034

+0

element.xpath ("cadena()") devuelve el mismo resultado que * .tostring(). Intenté xpath ("text()") que no devuelve el texto del elemento de anclaje, pero devuelve una lista de 2 cadenas. Gracias por señalar algunas cosas sin embargo. – user522034

5

parece un error lxml a mí, pero de acuerdo con el diseño si usted lee la documentación he resuelto como este :

def node_text(node): 
    if node.text: 
     result = node.text 
    else: 
     result = '' 
    for child in node: 
     if child.tail is not None: 
      result += child.tail 
    return result 
+1

No es un error, en realidad es la característica que le permite interponer texto entre subelementos al crear un elemento XML: http://stackoverflow.com/q/38520331/694360 – mmj

+0

Gracias por señalarlo. Supongo que eso es útil, pero sería mucho más claro si '.text' simplemente devolviera el texto completo y alguna otra propiedad adecuadamente nombrada contendría solo la parte hasta el primer subelemento. ¿Qué tal 'node.head'. Esto también da una pista de que lo que querrás ahora es 'child.tail' sin tener que stackoverflow primero. –

1
def get_text_recursive(node): 
    return (node.text or '') + ''.join(map(get_text_recursive, node)) + (node.tail or '') 
5

Como un servicio público a la gente que puede ser tan vago como yo. Aquí hay un código de arriba que puedes ejecutar.

from lxml import etree 

def get_text1(node): 
    result = node.text or "" 
    for child in node: 
     if child.tail is not None: 
      result += child.tail 
    return result 

def get_text2(node): 
    return ((node.text or '') + 
      ''.join(map(get_text2, node)) + 
      (node.tail or '')) 

def get_text3(node): 
    return (node.text or "") + "".join(
     [etree.tostring(child) for child in node.iterchildren()]) 


root = etree.fromstring(u"<td> text1 <a> link </a> text2 </td>") 

print root.xpath("string()") 
print root.xpath("text()") 
print get_text1(root) 
print get_text2(root) 
print etree.tostring(root, method = "text") 
print etree.tostring(root, method = "xml") 
print get_text3(root) 

de salida es:

snowy:rpg$ python test.py 
text1 link text2 
[' text1 ', ' text2 '] 
text1 text2 
text1 link text2 
text1 link text2 
<td> text1 <a> link </a> text2 </td> 
text1 <a> link </a> text2 
1
<td> text1 <a> link </a> text2 </td> 

Así es como es (espacio en blanco ignorando):

td.text == 'text1' 
a.text == 'link' 
a.tail == 'text2' 

Si no desea que un texto que está dentro de los elementos secundarios a continuación usted podría recoger solo sus colas:

text = td.text + ''.join([el.tail for el in td]) 
3

Otra cosa que parece estar funcionando bien para obtener el texto de un elemento es "".join(element.itertext())

0

Si el element es igual a <td>. Puedes hacer lo siguiente.

element.xpath('.//text()') 

Se le dará una lista de todos los elementos de texto desde self (el significado del punto). // significa que tomará todos los elementos y finalmente text() es la función para extraer texto.

0
element.xpath('normalize-space()') also works. 
+3

Solo pegar código no es suficiente. También deberías explicar por qué funciona :) –

Cuestiones relacionadas