2013-04-28 34 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'