為什麼使用BeautifulSoup時,把解析器換成lxml就出錯?

寫了一個爬蟲,用了BeautifulSoup解析html。要查找html中的第二個table。本來結果都對。想試試lxml。就安裝lxml後把soup = BeautifulSoup(html)#html.parser,lxml
換成了soup = BeautifulSoup(html,"lxml")。於是解析出錯了。
再換成soup = BeautifulSoup(html,"html.parser")又對了。
換回lxml,又錯。看來lxml是問題所在。

出錯部分的代碼是:

tables = soup.findAll("table",class_="tableList")
table = tables[1] #就是這行報錯

報錯信息:
Traceback (most recent call last):
File "parse.py", line 43, in &
l = parse_data(open("3.html",encoding="utf8"))
File "parse.py", line 15, in parse_data
table = tables[1]
IndexError: list index out of range

為什麼換成lxml就越界了,難道lxml的解析規則不一樣?


這個官方文檔上有說明的,不同的解析器之間是有差異的。

以下來自官方文檔:
Beautiful Soup 4.2.0 文檔

解析器之間的區別

Beautiful Soup為不同的解析器提供了相同的介面,但解析器本身時有區別的.同一篇文檔被不同的解析器解析後可能會生成不同結構的樹型文檔.區別最大的是HTML解析器和XML解析器,看下面片段被解析成HTML結構:


BeautifulSoup("&&&")
# &&&&&&&&&&

因為空標籤&不符合HTML標準,所以解析器把它解析成&&

同樣的文檔使用XML解析如下(解析XML需要安裝lxml庫).注意,空標籤&依然被保留,並且文檔前添加了XML頭,而不是被包含在&標籤內:

BeautifulSoup("&&&", "xml")
# &
# &&&

HTML解析器之間也有區別,如果被解析的HTML文檔是標準格式,那麼解析器之間沒有任何差別,只是解析速度不同,結果都會返回正確的文檔樹.

但是如果被解析文檔不是標準格式,那麼不同的解析器返回結果可能不同.下面例子中,使用lxml解析錯誤格式的文檔,結果&標籤被直接忽略掉了:


BeautifulSoup("&&", "lxml")
# &&&&&&

使用html5lib庫解析相同文檔會得到不同的結果:


BeautifulSoup("&&", "html5lib")
# &&&&&&

&&&&

html5lib庫沒有忽略掉&標籤,而是自動補全了標籤,還給文檔樹添加了&標籤.

使用pyhton內置庫解析結果如下:


BeautifulSoup("&&", "html.parser")
# &&

與lxml [7] 庫類似的,Python內置庫忽略掉了&標籤,與html5lib庫不同的是標準庫沒有嘗試創建符合標準的文檔格式或將文檔片段包含在&標籤內,與lxml不同的是標準庫甚至連&標籤都沒有嘗試去添加.

因為文檔片段「&&」是錯誤格式,所以以上解析方式都能算作」正確」,html5lib庫使用的是HTML5的部分標準,所以最接近」正確」.不過所有解析器的結構都能夠被認為是」正常」的.

不同的解析器可能影響代碼執行結果,如果在分發給別人的代碼中使用了 BeautifulSoup ,那麼最好註明使用了哪種解析器,以減少不必要的麻煩.


一樓@盧戰豪 已經說得比較清楚了,我想補充一點就是根據Beautiful Soup Documentation,如果你想知道自己的Beautiful Soup是怎麼解析html文件的話,可以用:

from bs4.diagnose import diagnose
data = open("bad.html").read()
diagnose(data)

# Diagnostic running on Beautiful Soup 4.2.0
# Python version 2.7.3 (default, Aug 1 2012, 05:16:07)
# I noticed that html5lib is not installed. Installing it may help.
# Found lxml version 2.3.2.0
#
# Trying to parse your data with html.parser
# Here"s what html.parser did with the document:
# ...

它會列印出你系統已有的解析器,並且根據已有解析器解析得到的結果。
溫馨提示:如果html文件較大,建議在終端將結果重定向到一個文件方便查看。如果lxml解析結果可以,盡量用lxml。因為lxml速度更快。


最近使用BeautifulSoup也出現了類似的問題,所以有此一答。

(BeautifulSoup 和 lxml 都是pip install的)

答主在做手上的一個爬蟲的時候,發現BeautifulSoup的lxml解析器經常會解析不到一些tag,一開始也認為是解析器的差異,暫時擱置了一下。

但是在處理一個文檔的時候,發現它連title都find不到了,於是就覺得有點奇怪,肯定不是解析器間差異的問題了。

把soup.prettify()列印出來一看:

很長的html變成soup就剩這麼點東西了。自然裡面有什麼也找不到了。

這一塊原本是這樣的:

解析器在第一個&之後就截止了。

那為什麼在這裡截止呢,顯然是因為中文。把幾個&里的中文變英文,輸出變這樣了:

&含中文,還是解析不到。

也就是說,lxml解析器遇到含中文標籤就截止了,後面的內容是它自己補全的

用chardet.detect()看了下html的編碼,是utf-8。據網上一些帖子所說,轉成Unicode試試:

這回倒是看到&了。有解釋說用lxml做之前必須utf8解碼,否則它會把』XXX』認為是結束tag。可是Unicode是』uXXXX』,應該也有這種情況吧。

結果到了後面一個地方又混亂了:

往下答主也不知道該怎麼辦了。幫你再邀請一下。


f調試時發現,有的網頁經過lxml解析後很多內容沒有了,換其他的解析器就可以。所以,我一般選取2~3個解析器。如果出錯就換另一個解析器。


能問下題主問題解決了嗎?我也遇到了一樣的問題,就是也是按xlml解析出來的網頁不全


昨天在解析素材公社的源碼時也遇到了,用lxml什麼鬼都沒找到,換成自帶的html.parse就好了。


推薦閱讀:

如何用python 寫一個爬蟲用來爬P 站特定標籤下的高贊作品?
scrapy遇到問題,希望得到大家幫助?
對於爬蟲項目,python 2和3哪個好些?
有c#基礎,最近對爬蟲感興趣,開始轉學python,求指導?

TAG:Python | 爬蟲計算機網路 | beautifulsoup |