2013-04-28 102 views
2

我对Python很新,但到底是什么......这是一个奇怪的问题,所以我会尽我所能地尽我所能地解释它:BeautifulSoup在修复损坏的标记时丢弃文本

我忙于尝试在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> 
... 

这是HTML的最后一块,从BeautifulSoup显示出来:

... 
<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。这可能是我如何处理事情的一个问题,但在这一点上,我令人难以置信地迷失了方向。

有谁知道什么可能导致这种情况发生?谢谢! :)

+0

如果你明确地传递HTML(包裹在''标签)作为一个字符串BeautifulSoup会发生什么? – 2013-04-28 23:04:44

+1

安装'html5lib',看看是否有帮助BeautifulSoup更轻松地解析它。 – Blender 2013-04-28 23:08:22

+0

@Blender,哇。那样做了。我从未想过......你能否做出答案,我会接受它? – Thanizer 2013-04-28 23:38:01

回答

5

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

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

+0

+1正确和简洁 – msw 2013-04-29 00:03:57

+0

花了无用的时间调试我的代码后,并最终在使用html5lib后解决...非常感谢你...代码重新写在一行只是:'汤= BeautifulSoup(html,“ html5lib“)'它已经完成了魔术......所有的汤都保持完好......之前错过了页面的很多部分。 – ihightower 2014-05-17 18:12:24

0

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可以通过name通过class但找不到标签:

<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'