BeautifulSoup用户的html5lib / lxml示例?

时间:2010-09-12 19:35:09

标签: python beautifulsoup lxml html5lib

我正试图从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 个答案:

答案 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文档,尤其是以下部分: