lxml не может разобрать <table>? - PullRequest
1 голос
/ 04 ноября 2010

Я хочу разобрать таблицы в html, но я обнаружил, что lxml не может его проанализировать? что не так?

# -*- coding: utf8 -*-
import urllib
import lxml.etree
keyword = 'lxml+tutorial'

url = 'http://www.baidu.com/s?wd='
if __name__ == '__main__':
    page = 0

    link = url + keyword + '&pn=' + str(page)

    f = urllib.urlopen(link)
    content = f.read()
    f.close()

    tree = lxml.etree.HTML(content)

    query_link = '//table'

    info_link = tree.xpath(query_link)

    print info_link

результат печати просто [] ...

Ответы [ 2 ]

3 голосов
/ 06 ноября 2010

lxml документация гласит : «Поддержка разбора поврежденного HTML полностью зависит от алгоритма восстановления libxml2. Это не ошибка lxml, если вы найдете документы, которые настолько сильно повреждены, что анализатор не может их обработать. Также нет гарантии, что результирующее дерево будет содержать все данные из исходного документа. Парсеру, возможно, придется отбросить серьезно сломанные части при попытке продолжить анализ. "

И, конечно же, HTML-код, возвращенный Baidu, недействителен: валидатор W3C сообщает"173 ошибки, 7 предупреждений". Я не знаю (и не исследовал), вызвали ли эти конкретные ошибки вашу проблему с lxml, потому что я думаю, что ваша стратегия использования lxml для анализа HTML, найденного «в дикой природе» (который почти всегда недействителен), обречена .

Для анализа недопустимого HTML вам нужен анализатор, который реализует ( на удивление странный! ) алгоритм восстановления ошибок HTML. Поэтому я рекомендую заменить lxml на html5lib , который без проблем обрабатывает неверный HTML-код Baidu:

>>> import urllib
>>> from html5lib import html5parser, treebuilders
>>> p = html5parser.HTMLParser(tree = treebuilders.getTreeBuilder('dom'))
>>> dom = p.parse(urllib.urlopen('http://www.baidu.com/s?wd=foo').read())
>>> len(dom.getElementsByTagName('table'))
12
2 голосов
/ 04 ноября 2010

Я вижу несколько мест, где код может быть улучшен, но, на ваш вопрос, вот мои предложения:

  1. Используйте lxml.html.parse(link) вместо lxml.etree.HTML(content), чтобы можно было задействовать все автоматы "просто работает" (например, правильно обрабатывать объявления кодировки символов в заголовках)

  2. Попробуйте использовать tree.findall(".//table") вместо tree.xpath("//table"). Я не уверен, будет ли это иметь значение, но я просто использовал этот синтаксис в своем собственном проекте несколько часов назад без проблем и, в качестве бонуса, он совместим с API-интерфейсами не-LXML ElementTree.

Другая важная вещь, которую я бы предложил, это использование встроенных функций Python для создания URL-адресов, чтобы вы могли быть уверены, что создаваемый URL-адрес действителен и правильно экранирован при любых обстоятельствах.

Если LXML не может найти таблицу и браузер показывает, что таблица существует, я могу только представить, что это одна из этих трех проблем:

  1. Неверный запрос. LXML получает страницу без таблицы. (например, ошибка 404 или 500)
  2. Плохой разбор. Что-то в странице сбило с толку lxml.etree.HTML при прямом вызове.
  3. Необходим Javascript. Возможно, таблица генерируется на стороне клиента.
...