我正试图从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。
有人能让我回到正轨吗?
答案 0 :(得分:6)
您可以使用以下命令关闭命名空间:
etree_document = html5lib.parse(t, treebuilder="lxml", namespaceHTMLElements=False)
答案 1 :(得分:5)
通常,对HTML使用lxml.html
。然后你不必担心生成自己的解析器&amp;担心命名空间。
>>> 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
答案 2 :(得分: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 documentation提供了有关如何使用XML命名空间的更多信息。
答案 3 :(得分:1)
我意识到这是一个古老的问题,但我来到这里是为了寻找我在其他任何地方都找不到的信息。我试图用BeautifulSoup刮掉一些东西,但它在一些粗糙的HTML上窒息。默认的html解析器显然比其他可用的解析器松散。一个通常首选的解析器是lxml,我相信它会产生与浏览器预期相同的解析。 BeautifulSoup允许您指定lxml作为源解析器,但使用它需要一些工作。
首先,您需要html5lib并且还必须安装lxml。虽然html5lib准备使用lxml(和其他一些库),但两者并没有打包在一起。 [对于Windows用户,即使我不喜欢使用Win依赖项,我通常通过在与项目相同的目录中创建库来获取库,我强烈建议使用pip;相当无痛;我认为您需要管理员访问权限。]
然后你需要写这样的东西:
import urllib2
from bs4 import BeautifulSoup
import html5lib
from html5lib import sanitizer
from html5lib import treebuilders
from lxml import etree
url = 'http://...'
content = urllib2.urlopen(url)
parser = html5lib.HTMLParser(tokenizer=sanitizer.HTMLSanitizer,
tree=treebuilders.getTreeBuilder("lxml"),
namespaceHTMLElements=False)
htmlData = parser.parse(content)
htmlStr = etree.tostring(htmlData)
soup = BeautifulSoup(htmlStr, "lxml")
然后享受你美丽的汤!
请注意解析器上的namespaceHTMLElements = false选项。这很重要,因为lxml适用于XML而不仅仅是HTML。因此,它会将它提供的所有标记标记为属于HTML命名空间。标签看起来像(例如)
<html:li>
和BeautifulSoup效果不佳。
答案 4 :(得分:0)
尝试:
root.find('.//{http://www.w3.org/1999/xhtml}tr')
您必须指定命名空间而不是命名空间前缀(html:tr
)。有关更多信息,请参阅lxml文档,尤其是以下部分: