【问题标题】:How to prevent BeautifulSoup4 from adding extra <html><body> tags to the soup? [duplicate]如何防止 BeautifulSoup4 在汤中添加额外的 <html><body> 标签? [复制]
【发布时间】:2013-04-05 12:51:09
【问题描述】:

在 BeautifulSoup 3 之前的版本中,我可以获取任何 HTML 块并以这种方式获取字符串表示形式:

from BeautifulSoup import BeautifulSoup
soup3 = BeautifulSoup('<div><b>soup 3</b></div>')
print unicode(soup3)
    '<div><b>soup</b></div>'

但是对于 BeautifulSoup4,相同的操作会创建额外的标签:

from bs4 import BeautifulSoup
soup4 = BeautifulSoup('<div><b>soup 4</b></div>')
print unicode(soup4)
    '<html><body><div><b>soup 4</b></div></body></html>'
     ^^^^^^^^^^^^                        ^^^^^^^^^^^^^^ 

我不需要 BS4 添加的外部 &lt;html&gt;&lt;body&gt;..&lt;/body&gt;&lt;/html&gt; 标签。我查看了 BS4 文档并在类内部进行了搜索,但找不到任何用于抑制输出中额外标签的设置。我该怎么做?降级到 v3 不是一种选择,因为 BS3 中使用的 SGML 解析器不如 BS4 中的 lxmlhtml5lib 解析器好。

【问题讨论】:

  • 我认为是 stackoverflow.com/q/14822188/57318 的欺骗?
  • @Xymotech 是的,但是在该问题中建议的解决方案是更改解析器,恕我直言不是最佳选择。例如,因为lxml 真的很酷.. 显然我需要做的是soup2.html.body.contents[0] 但有更好的选择吗?
  • 啊,我没有意识到它实际上改变了它使用的解析器。嗯......它还说你可以做soup.body.next。这行得通吗?
  • @Xymotech: soup.body.next 完成了这项工作!谢谢 Xymotech
  • @ccpizza:您只是需要它在您的计算机上工作,还是需要分发它?

标签: python beautifulsoup


【解决方案1】:

如果您希望您的代码在每个人的机器上运行,无论他们安装了哪些解析器等(基于libxml2 2.9 与 2.8 构建的相同lxml 版本的行为非常不同,stdlib @ 987654324@ 在 2.7.2 和 2.7.3 之间发生了一些根本性的变化,...),您几乎需要处理所有合法结果。

如果你知道你有一个片段,像这样的东西会给你这个片段:

soup4 = BeautifulSoup('<div><b>soup 4</b></div>')
if soup4.body:
    return soup4.body.next
elif soup4.html:
    return soup4.html.next
else:
    return soup4

当然,如果您知道您的片段是单个 div,那就更容易了——但是想出一个您知道的用例并不容易:

soup4 = BeautifulSoup('<div><b>soup 4</b></div>')
return soup4.div

如果您想知道为什么会发生这种情况:

BeautifulSoup 用于解析 HTML 文档。 HTML 片段不是有效的文档。它非常接近文档,但这还不足以保证您会得到您所提供的准确信息。

正如Differences between parsers 所说:

HTML 解析器之间也存在差异。如果你给 Beautiful Soup 一个格式完美的 HTML 文档,这些差异就无关紧要了。一个解析器会比另一个更快,但它们都会为您提供一个看起来与原始 HTML 文档完全相同的数据结构。

但是如果文档的格式不完美,不同的解析器会给出不同的结果。

因此,虽然没有记录这种确切的差异,但它只是某种特殊情况。

【讨论】:

  • 谢谢!这很困难,但我几乎设法说服自己 BS3 做错了。或者更准确地说,它所依赖的解析器(SGML)做错了。事实上,BS3 中的 SGML 解析器很糟糕,有时会因为一些无效的标签或字符而忽略整个标记块,而这正是让我想到 BS4 的原因,它在相同的标记上做得更好。
  • 好吧,文档非常小心地解释说,当您提供无效的 HTML 时,您实际上没有权利期待任何具体的东西……只是希望得到一些有用的东西。所以,BS3 所做的(在这种情况下)并不是真正的“错误”,它只是不比所有使用 BS4 的各种解析器所做的更正确。
  • 请注意,如果正文中有多个元素,此响应实际上会被破坏。如果你有&lt;h1&gt;a&lt;/h1&gt;&lt;h1&gt;b&lt;/h1&gt;,它只会返回&lt;h1&gt;a&lt;/h1&gt;
  • @Wolph:是的。作为单个(有效)HTML 子树的片段和作为多个(有效)HTML 子树的森林的片段是不同的,相同的解析代码不一定适用于两者……
【解决方案2】:

正如旧的BeautifulStoneSoup documentation 所述:

BeautifulSoup 类充满了类似 Web 浏览器的启发式方法,用于预测 HTML 作者的意图。但是 XML 没有固定的标记集,因此这些启发式方法不适用。所以 BeautifulSoup 对 XML 的处理不是很好。

使用 BeautifulStoneSoup 类来解析 XML 文档。这是一个通用类,没有任何 XML 方言的特殊知识和非常简单的标签嵌套规则...

而在BeautifulSoup4 docs

不再有用于解析 XML 的 BeautifulStoneSoup 类。要解析 XML,您将“xml”作为第二个参数传递给 BeautifulSoup 构造函数。出于同样的原因,BeautifulSoup 构造函数不再识别 isHTML 参数。

也许这会产生你想要的。

【讨论】:

  • 如果你真的有完全有效的 X(HT)ML,这会有点工作......但它会在开头添加一个 &lt;?xml…?&gt;,这比 @987654324 更难解决@(有或没有head)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-30
  • 2021-12-18
  • 2018-03-09
  • 1970-01-01
  • 2013-11-08
  • 2012-11-03
  • 1970-01-01
相关资源
最近更新 更多