BeautifulSoup用户的html5lib/lxml示例?
我想要逐渐不再依赖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