【问题标题】:BeautifulSoup drops text when fixing up broken markupBeautifulSoup 在修复损坏的标记时丢弃文本
【发布时间】:2013-04-28 22:55:47
【问题描述】:

我对 Python 还是很陌生,但是这到底是怎么回事......这是一个奇怪的问题,所以我会尽我所能地解释它:

我正忙着尝试用 Python 编写一个脚本来检查网页的特定更改(基本上是从 0 翻转到 1 的数字)。当该更改发生时,脚本将继续执行其他操作。不幸的是,我还没有达到这一点,因为我什至无法解析 HTML,因为当BeautifulSoup 获取它时,很多 HTML 都丢失了! (至少,这是我声称的。)

让我们逐步完成:我为此使用BeautifulSoupMechanize。首先,我在网页上找到一个表单并选择它,根据需要更改表单中的控件。 (我已验证所有控件都按预期更改。)在此之后,我提交表单,然后调用我编写的名为 process_results() 的辅助函数:

...
form = list(client.forms())[1]
client.select_form('ttform');
...
# Modify controls
...
client.submit()
process_results(client)

process_results() 只检查客户端返回的内容。首先,根据表单中输入的内容,您可能会得到无效的搜索结果,所以我想搜索网页上显示的错误消息,看看它是否存在。我使用BeautifulSoup 来做到这一点:

# Processes search results.
def process_serach_results(cli):

    html = cli.response().read()
    soup = BeautifulSoup(html)
    ...

评估相关代码是否出现在页面上的语句如下所示:

...
if (soup.find('td', attr = {'class' : 'msgarea'}) != None):
    # Do something...
    ...

这永远不会评估为真,因为它找不到我描述的标签。我决定直接打印来自MechanizeBeautifulSoup 的回复,这就是我得到的(缩短的):

Mechanize 打印出我要查找的代码,这意味着响应正确返回:

...
<TD class=msgarea>
<B class=important_msg>There was a problem with your request:</B>
<BR>
<BR>
<li class=red_msg>...</li>
...
</TD></TR></TABLE><P></DIV>
...

这是从BeautifulSoup 显示的最后一段 HTML:

...
<span class="pageheaderlinks">
<a ... > MENU </a>
|
<a ... > SITE MAP </a>
|
</span></td></tr></table></div></body></html>

事实上,这是来自 Mechanize 的相同 HTML:

...
<SPAN class="pageheaderlinks">
<A ... >MENU</A>
|
<A ... >SITE MAP</A>
|
<--! Notice how this continues -->
<A ... >HELP</A>
|
<A ... >EXIT</A>
</span>
...

问题是BeautifulSoup 似乎在Mechanize 的浏览器报告的内容末尾省略了一大段HTML。这可能是我做事方式的问题,但在这一点上,我非常迷茫。

有谁知道导致这种情况发生的原因是什么?谢谢! :)

【问题讨论】:

  • 如果您将 HTML(包装在 &lt;html&gt;&lt;body&gt; 标签中)作为字符串显式传递给 BeautifulSoup,会发生什么?
  • 安装 html5lib 看看这是否有助于 BeautifulSoup 更宽松地解析它。
  • @Blender,哇。做到了。我从来没有想过......你能做出这样的答案,我会接受吗?

标签: python html-parsing beautifulsoup


【解决方案1】:

BeautifulSoup 支持a bunch of different HTML parsers。 Python 的内置解析器不是很快也不是很宽松(这意味着它很难理解无效的 HTML),所以它会阻塞你的 HTML。

尝试安装lxml,它更宽松,速度更快。如果这不起作用,html5lib 是您最好的选择,因为它是最宽松的,但也是最慢的。

【讨论】:

  • 在花费了无用的时间调试我的代码之后......终于在使用 html5lib 后解决了......非常感谢......代码仅用一行重写为:soup = BeautifulSoup(html, "html5lib"),它已经完成了魔法……所有的汤都保持原样……以前错过了页面的许多部分。
【解决方案2】:

Blender 的回答是正确的,但是这段代码显示了旧解析器对标记的破坏程度,并且在寻找类似问题时可能很有用。

# fails with bs3, works with bs4
bs3 = True

if bs3:
    from BeautifulSoup import BeautifulSoup 
else:
    from bs4 import BeautifulSoup 

mechanize = """
    <TD class=msgarea>
    <B class=important_msg>There was a problem with your request:</B>
    <BR>
    <BR>
    <li class=red_msg>...</li>
    </TD></TR></TABLE><P></DIV>"""


soup = BeautifulSoup(mechanize) 
# the default parser worked just fine, see?
print soup.prettify()

print 'is important_msg?', soup.find('b').attrs
print 'is msgarea?', soup.find('td').attrs
print 'is td?', soup.find(class_='msgarea').name
print 'is contents?', soup.find('td', class_='msgarea').contents[:5], '...'

我花了一些时间来调试,因为 bs4 没有失败,所以我想我可能会拯救下一个来这里的人。这是使用 bs3 的真正奇怪的输出,它可以通过class 找到标签,但不能通过name

<td class="msgarea">
 <b class="important_msg">
  There was a problem with your request:
 </b>
 <br />
 <br />
 <li class="red_msg">
  ...
 </li>
</td>
<p>
</p>
is important_msg? [(u'class', u'important_msg')]
is msgarea? [(u'class', u'msgarea')]
is td?
Traceback (most recent call last):
  File "bs-fail.py", line 24, in <module>
    print 'is td?', soup.find(class_='msgarea').name
AttributeError: 'NoneType' object has no attribute 'name'

【讨论】:

    猜你喜欢
    • 2019-07-07
    • 1970-01-01
    • 2019-02-01
    • 2022-07-25
    • 2010-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多