2010-04-01 6 views
15

Estoy tratando de usar html5lib para analizar una página html en algo que puedo consultar con xpath. html5lib tiene documentación casi nula y he pasado demasiado tiempo tratando de resolver este problema. objetivo final es sacar la segunda fila de una tabla:¿Cómo puedo analizar HTML con html5lib y consultar el HTML analizado con XPath?

<html> 
    <table> 
     <tr><td>Header</td></tr> 
     <tr><td>Want This</td></tr> 
    </table> 
</html> 

Así que vamos a probarlo:

>>> doc = html5lib.parse('<html><table><tr><td>Header</td></tr><tr><td>Want This</td> </tr></table></html>', treebuilder='lxml') 
>>> doc 
<lxml.etree._ElementTree object at 0x1a1c290> 

que se ve bien, vamos a ver qué más tenemos:

>>> root = doc.getroot() 
>>> print(lxml.etree.tostring(root)) 
<html:html xmlns:html="http://www.w3.org/1999/xhtml"><html:head/><html:body><html:table><html:tbody><html:tr><html:td>Header</html:td></html:tr><html:tr><html:td>Want This</html:td></html:tr></html:tbody></html:table></html:body></html:html> 

LOL WUT?

en serio. Estaba planeando usar algún xpath para obtener los datos que quiero, pero parece que no funciona. ¿Entonces Que puedo hacer? Estoy dispuesto a probar diferentes bibliotecas y enfoques.

Respuesta

19

La falta de documentación es una buena razón para evitar una biblioteca OMI, no importa lo bueno que es . ¿Estás casado con el uso de html5lib? ¿Has mirado lxml.html?

Aquí es una manera de hacer esto con lxml:

from lxml import html 
tree = html.fromstring(text) 
[td.text for td in tree.xpath("//td")] 

Resultado:

['Header', 'Want This'] 
-3

intente utilizar jquery. y puedes recuperar todos los elementos. alternativamente, puede poner una identificación en su fila y sacarla.

1) ... ...

$ ("TD") [1] .innerHTML será lo que quiere

2) ... ...

$ ("#blah"). texto() será lo que quiere

+0

creo que la solicitud era para una solución de Python. –

1

creo que se puede hacer una búsqueda CSS en objetos LXML .. como así

elements = root.cssselect('div.content') 
data = elements[0].text 
2

Con BeautifulSoup, se puede hacer eso con

>>> soup = BeautifulSoup.BeautifulSoup('<html><table><tr><td>Header</td></tr><tr><td>Want This</td></tr></table></html>') 
>>> soup.findAll('td')[1].string 
u'Want This' 
>>> soup.findAll('tr')[1].td.string 
u'Want This' 

(Obviamente eso es un ejemplo muy crudo, pero ya.)

3

Siempre recomiendo probar lxml biblioteca. Es sorprendentemente rápido y tiene muchas características.

También tiene soporte para el analizador html5lib si necesita que: html5parser

>>> from lxml.html import fromstring, tostring 

>>> html = """ 
... <html> 
...  <table> 
...   <tr><td>Header</td></tr> 
...   <tr><td>Want This</td></tr> 
...  </table> 
... </html> 
... """ 
>>> doc = fromstring(html) 
>>> tr = doc.cssselect('table tr')[1] 
>>> print tostring(tr) 
<tr><td>Want This</td></tr> 
+1

Así es como lo haría, excepto que usaría "print doc.cssselect ('tr') [1] .text_content()" para obtener los contenidos de la segunda fila, en lugar de que lxml muestre el HTML . –

15

Lo que se quiere utilizar es el argumento namespaceHTMLElements, que por alguna razón los valores por defecto en True.

doc = html5lib.parse('''<html> 
    <table> 
     <tr><td>Header</td></tr> 
     <tr><td>Want This</td></tr> 
    </table> 
</html> 
''', treebuilder='lxml', namespaceHTMLElements=False) 

print lxml.html.tostring(doc) 

Probablemente sea aún más fácil de usar lxml.html sin embargo.

+0

La respuesta más relevante. Muchas gracias! – gorlum0

+2

El valor predeterminado es 'Verdadero' porque la especificación HTML define esos elementos en el espacio de nombre HTML; las herramientas existentes de Python requieren que no lo estén, por lo que existe la opción. – gsnedders

0

Como html5lib (de forma predeterminada) crea árboles que contienen información de espacio de nombres (correcta), también tiene espacios de nombres (el derecho) en sus consultas.

Ejemplo con una consulta XPath:

import html5lib 
inp='''<html> 
    <table> 
     <tr><td>Header</td></tr> 
     <tr><td>Want This</td></tr> 
    </table> 
</html>''' 
xns = '{http://www.w3.org/1999/xhtml}' 
d = html5lib.parse(inp) 
s = d.findall('.//{}td'.format(xns))[-1].text 
print(s) 

Salida:

Want This

El mismo resultado sin XPath:

s = d.find(xns+'body').find(xns+'table').find(xns+'tbody') \ 
    .findall(xns+'tr')[-1].find(xns+'td').text 

Como alternativa, también se puede decir html5lib para evitar la adición de cualquier información del espacio de nombres durante el análisis:

d = html5lib.parse(inp, namespaceHTMLElements=False) 
s = d.findall('.//td')[-1].text 
print(s) 

Salida:

Want This
Cuestiones relacionadas