Как я могу проанализировать HTML с html5lib и запросить проанализированный HTML с XPath? - PullRequest
16 голосов
/ 01 апреля 2010

Я пытаюсь использовать html5lib для анализа html-страницы, чтобы я мог запросить ее с помощью xpath. html5lib имеет почти нулевую документацию, и я потратил слишком много времени, пытаясь решить эту проблему. Конечная цель - вытащить второй ряд таблицы:

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

так что давайте попробуем:

>>> 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>

это выглядит хорошо, давайте посмотрим, что еще у нас есть:

>>> 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?

серьезно. Я планировал использовать некоторый xpath для получения нужных мне данных, но, похоже, это не сработало. Так что я могу сделать? Я готов попробовать разные библиотеки и подходы.

Ответы [ 7 ]

19 голосов
/ 01 апреля 2010

Отсутствие документации - это хороший повод избегать библиотеки IMO, какой бы крутой она ни была. Вы намерены использовать html5lib? Вы смотрели на lxml.html ?

Вот способ сделать это с помощью lxml:

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

Результат:

['Header', 'Want This']
17 голосов
/ 22 февраля 2011

То, что вы хотите использовать, это аргумент namespaceHTMLElements, который по какой-то причине по умолчанию равен 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)

Однако, вероятно, все еще проще использовать lxml.html.

3 голосов
/ 01 апреля 2010

Я всегда рекомендую попробовать lxml библиотеку. Это невероятно быстро и имеет много функций.

Также имеется поддержка парсера html5lib, если вам это необходимо: 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>
2 голосов
/ 01 апреля 2010

С BeautifulSoup , вы можете сделать это с

>>> 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'

(Очевидно, это очень грубый пример, но да.)

1 голос
/ 19 апреля 2017

Поскольку html5lib (по умолчанию) создает деревья, которые содержат (правильную) информацию о пространстве имен, вы также указываете (правильные) пространства имен в своих запросах.

Пример с запросом 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)

Выход:

Want This

Тот же результат без XPath:

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

В качестве альтернативы, вы также можете указать html5lib избегать добавления какой-либо информации о пространстве имен во время синтаксического анализа:

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

Выход:

Want This
1 голос
/ 01 апреля 2010

Я считаю, что вы можете сделать поиск CSS по объектам lxml .. как это так

elements = root.cssselect('div.content')
data = elements[0].text
0 голосов
/ 01 апреля 2010

попробуйте использовать jquery.и вы можете получить все элементы.поочередно, вы можете поставить id в строку и вытащить его.

1) ... ...

$ ("td") [1] .innerHTML будет тем, чем выхочу

2) ... ...

$ ("# бла"). text () будет то, что вы хотите

...