BeautifulSoup用户的html5lib/lxml示例?

1 投票
5 回答
5157 浏览
提问于 2025-04-16 04:03

我想要逐渐不再依赖BeautifulSoup,虽然我很喜欢它,但感觉它的支持有点不够。我现在想用html5lib和lxml来处理网页,但我不知道怎么用“find”和“findall”这两个操作。

我查看了html5lib的文档,写了一个测试程序:

import cStringIO

f = cStringIO.StringIO()
f.write("""
  <html>
    <body>
      <table>
       <tr>
          <td>one</td>
          <td>1</td>
       </tr>
       <tr>
          <td>two</td>
          <td>2</td
       </tr>
      </table>
    </body>
  </html>
  """)
f.seek(0)

import html5lib
from html5lib import treebuilders
from lxml import etree  # why?

parser = html5lib.HTMLParser(tree=treebuilders.getTreeBuilder("lxml"))
etree_document = parser.parse(f)

root = etree_document.getroot()

root.find(".//tr")

但是这个程序返回的是None。我发现如果我用etree.tostring(root),我能拿到所有的数据,但所有的标签前面都有个html的前缀(比如<html:table>)。可是当我用root.find(".//html:tr")时,却出现了KeyError的错误。

有人能帮我指点一下吗?

5 个回答

3

看起来使用“lxml”的 html5lib TreeBuilder 会让 html5lib 在 XHTML 命名空间中构建树。这是有道理的,因为 lxml 是一个 XML 库,而 XHTML 就是把 HTML 表示成 XML 的一种方式。你可以用 lxml 的 qname 语法配合 find() 方法来做一些事情,比如:

root.find('.//{http://www.w3.org/1999/xhtml}tr')

或者你也可以使用 lxml 的完整 XPath 函数来做类似的事情:

root.xpath('.//html:tr', namespaces={'html': 'http://www.w3.org/1999/xhtml'})

如果想了解更多关于 lxml 如何使用 XML 命名空间的信息,可以查看 lxml 的文档

6

你可以通过这个命令来关闭命名空间功能:

etree_document = html5lib.parse(t, treebuilder="lxml", namespaceHTMLElements=False)
5

一般来说,处理HTML时可以使用 lxml.html。这样你就不用担心自己写解析器或者处理命名空间的问题了。

>>> import lxml.html as l
>>> doc = """
...    <html><body>
...    <table>
...      <tr>
...        <td>one</td>
...        <td>1</td>
...      </tr>
...      <tr>
...        <td>two</td>
...        <td>2</td
...      </tr>
...    </table>
...    </body></html>"""
>>> doc = l.document_fromstring(doc)
>>> doc.finall('.//tr')
[<Element tr at ...>, <Element tr at ...>] #doctest: +ELLIPSIS

顺便说一下,lxml.html 还支持使用CSS选择器,这种写法我觉得更简单易懂。

>>> doc.cssselect('tr')
[<Element tr at ...>, <Element tr at ...>] #doctest: +ELLIPSIS

撰写回答