[英]BeautifulSoup - lxml and html5lib parsers scraping differences
[英]html5lib/lxml examples for BeautifulSoup users?
我正在尝试从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")
引发root.find(".//html:tr")
。
有人可以让我回到正确的轨道吗?
您可以使用以下命令关闭名称空间: etree_document = html5lib.parse(t, treebuilder="lxml", namespaceHTMLElements=False)
通常,将lxml.html
用于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
看来使用“ 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名称空间的更多信息。
我意识到这是一个古老的问题,但我来这里的目的是寻求在其他任何地方都找不到的信息。 我试图用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不能很好地工作。
尝试:
root.find('.//{http://www.w3.org/1999/xhtml}tr')
您必须指定名称空间,而不是名称空间前缀( html:tr
)。 有关更多信息,请参见lxml文档,尤其是本节:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.