lxml 无法解析 <table>?

1 投票
2 回答
1745 浏览
提问于 2025-04-16 06:32

我想解析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 个回答

2

我看到你代码里有几个地方可以改进,不过针对你的问题,我有以下建议:

  1. lxml.html.parse(link) 来代替 lxml.etree.HTML(content),这样可以让一些自动处理的功能正常工作。(比如,正确处理头部的字符编码声明)

  2. 试试用 tree.findall(".//table") 而不是 tree.xpath("//table")。我不确定这样做是否会有区别,但我刚刚在自己的项目中用这个语法没有问题,而且它也能和非LXML的ElementTree API兼容。

还有一个主要的建议是,使用Python内置的函数来构建URL,这样你可以确保你构建的URL在任何情况下都是有效的,并且正确转义。

如果LXML找不到表格,而浏览器却显示有表格,我只能想象可能是这三种问题之一:

  1. 请求错误。LXML获取的页面里没有表格。(比如,错误404或500)
  2. 解析错误。页面的某些内容让 lxml.etree.HTML 在直接调用时感到困惑。
  3. 需要JavaScript。也许这个表格是客户端生成的。
3

lxml的文档上说:“解析损坏的HTML的能力完全依赖于libxml2的恢复算法。如果你发现某些文档损坏得太厉害,以至于解析器无法处理,那不是lxml的错。也不能保证最终得到的树结构会包含原始文档中的所有数据。解析器在努力解析时,可能会不得不放弃一些严重损坏的部分。”

果然,百度返回的HTML是无效的:W3C的验证工具报告了“173个错误,7个警告”。我不知道(也没有调查过)这些具体的错误是否导致了你在使用lxml时遇到的问题,因为我认为你用lxml来解析“野生”的HTML(几乎总是无效的)这个策略是注定要失败的。

要解析无效的HTML,你需要一个实现了(非常奇怪的!)HTML错误恢复算法的解析器。所以我建议用html5lib来替换lxml,它可以毫无问题地处理百度的无效HTML:

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

撰写回答