1

我正试图摆脱 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")

但这返回无。我注意到,如果我这样做,etree.tostring(root)我会取回所有数据,但我所有的标签都以html(例如<html:table>)开头。但root.find(".//html:tr")抛出一个 KeyError。

有人可以让我回到正确的轨道上吗?

4

5 回答 5

6

您可以使用以下命令关闭命名空间: etree_document = html5lib.parse(t, treebuilder="lxml", namespaceHTMLElements=False)

于 2011-05-17T22:17:57.350 回答
5

通常,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
于 2010-09-12T23:06:38.030 回答
3

似乎使用“lxml”html5libTreeBuilder会导致 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 命名空间的信息。

于 2010-09-12T20:09:01.277 回答
2

我意识到这是一个老问题,但我来这里是为了寻找我在其他任何地方都找不到的信息。我试图用 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 将无法正常工作。

于 2015-07-13T03:59:23.203 回答
0

尝试:

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

您必须指定命名空间而不是命名空间前缀 ( html:tr)。有关更多信息,请参阅 lxml 文档,尤其是以下部分:

于 2010-09-12T19:57:00.350 回答