Как я могу анализировать HTML с помощью html5lib и запрашивать анализируемый HTML с помощью XPath?

Я пытаюсь использовать 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 для получения данных, которые я хочу, но это, похоже, не работает. Так что я могу сделать? Я готов попробовать разные библиотеки и подходы.

Ответы

Ответ 1

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

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

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

Результат:

['Header', 'Want This']

Ответ 2

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

Я всегда рекомендую попробовать библиотеку 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>

Ответ 4

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

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

Ответ 5

Я считаю, что вы можете выполнить поиск css на объектах lxml.. так

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

Ответ 6

Так как 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

Ответ 7

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

1)......

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

2)......

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