# 常見問題
## 代碼診斷
如果想知道Beautiful Soup到底怎樣處理一份文檔,可以將文檔傳入 `diagnose()` 方法(Beautiful Soup 4.2.0中新增),Beautiful Soup會輸出一份報告,說明不同的解析器會怎樣處理這段文檔,并標出當前的解析過程會使用哪種解析器:
```
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:
# ...
```
`diagnose()` 方法的輸出結果可能幫助你找到問題的原因,如果不行,還可以把結果復制出來以便尋求他人的幫助
## 文檔解析錯誤
文檔解析錯誤有兩種.一種是崩潰,Beautiful Soup嘗試解析一段文檔結果卻拋除了異常,通常是 `HTMLParser.HTMLParseError` .還有一種異常情況,是Beautiful Soup解析后的文檔樹看起來與原來的內容相差很多.
這些錯誤幾乎都不是Beautiful Soup的原因,這不會是因為Beautiful Soup得代碼寫的太優秀,而是因為Beautiful Soup沒有包含任何文檔解析代碼.異常產生自被依賴的解析器,如果解析器不能很好的解析出當前的文檔,那么最好的辦法是換一個解析器.更多細節查看 [安裝解析器](#id9) 章節.
最常見的解析錯誤是 `HTMLParser.HTMLParseError: malformed start tag` 和 `HTMLParser.HTMLParseError: bad end tag` .這都是由Python內置的解析器引起的,解決方法是 [安裝lxml或html5lib](#id9)
最常見的異常現象是當前文檔找不到指定的Tag,而這個Tag光是用眼睛就足夠發現的了. `find_all()` 方法返回 [] ,而 `find()` 方法返回 None .這是Python內置解析器的又一個問題: 解析器會跳過那些它不知道的tag.解決方法還是 [安裝lxml或html5lib](#id9)
## 版本錯誤
* `SyntaxError: Invalid syntax` (異常位置在代碼行: `ROOT_TAG_NAME = u'[document]'` ),因為Python2版本的代碼沒有經過遷移就在Python3中窒息感
* `ImportError: No module named HTMLParser` 因為在Python3中執行Python2版本的Beautiful Soup
* `ImportError: No module named html.parser` 因為在Python2中執行Python3版本的Beautiful Soup
* `ImportError: No module named BeautifulSoup` 因為在沒有安裝BeautifulSoup3庫的Python環境下執行代碼,或忘記了BeautifulSoup4的代碼需要從 `bs4` 包中引入
* `ImportError: No module named bs4` 因為當前Python環境下還沒有安裝BeautifulSoup4
## 解析成XML
默認情況下,Beautiful Soup會將當前文檔作為HTML格式解析,如果要解析XML文檔,要在 `BeautifulSoup` 構造方法中加入第二個參數 “xml”:
```
soup = BeautifulSoup(markup, "xml")
```
當然,還需要 [安裝lxml](#id9)
## 解析器的錯誤
* 如果同樣的代碼在不同環境下結果不同,可能是因為兩個環境下使用不同的解析器造成的.例如這個環境中安裝了lxml,而另一個環境中只有html5lib, [解析器之間的區別](#id49) 中說明了原因.修復方法是在 `BeautifulSoup` 的構造方法中中指定解析器
* 因為HTML標簽是 [大小寫敏感](http://www.w3.org/TR/html5/syntax.html#syntax) 的,所以3種解析器再出來文檔時都將tag和屬性轉換成小寫.例如文檔中的 `<TAG></TAG>` 會被轉換為 `<tag></tag>` .如果想要保留tag的大寫的話,那么應該將文檔 [解析成XML](#xml) .
## 雜項錯誤
* `UnicodeEncodeError: 'charmap' codec can't encode character u'\xfoo' in position bar` (或其它類型的 `UnicodeEncodeError` )的錯誤,主要是兩方面的錯誤(都不是Beautiful Soup的原因),第一種是正在使用的終端(console)無法顯示部分Unicode,參考 [Python wiki](http://wiki.Python.org/moin/PrintFails) ,第二種是向文件寫入時,被寫入文件不支持部分Unicode,這時只要用 `u.encode("utf8")` 方法將編碼轉換為UTF-8.
* `KeyError: [attr]` 因為調用 `tag['attr']` 方法而引起,因為這個tag沒有定義該屬性.出錯最多的是 `KeyError: 'href'` 和 `KeyError: 'class'` .如果不確定某個屬性是否存在時,用 `tag.get('attr')` 方法去獲取它,跟獲取Python字典的key一樣
* `AttributeError: 'ResultSet' object has no attribute 'foo'` 錯誤通常是因為把 `find_all()` 的返回結果當作一個tag或文本節點使用,實際上返回結果是一個列表或 `ResultSet` 對象的字符串,需要對結果進行循環才能得到每個節點的 `.foo` 屬性.或者使用 `find()` 方法僅獲取到一個節點
* `AttributeError: 'NoneType' object has no attribute 'foo'` 這個錯誤通常是在調用了 `find()` 方法后直節點取某個屬性 .foo 但是 `find()` 方法并沒有找到任何結果,所以它的返回值是 `None` .需要找出為什么 `find()` 的返回值是 `None` .
## 如何提高效率
Beautiful Soup對文檔的解析速度不會比它所依賴的解析器更快,如果對計算時間要求很高或者計算機的時間比程序員的時間更值錢,那么就應該直接使用 [lxml](http://lxml.de/) .
換句話說,還有提高Beautiful Soup效率的辦法,使用lxml作為解析器.Beautiful Soup用lxml做解析器比用html5lib或Python內置解析器速度快很多.
安裝 [cchardet](http://pypi.Python.org/pypi/cchardet/) 后文檔的解碼的編碼檢測會速度更快
[解析部分文檔](#id58) 不會節省多少解析時間,但是會節省很多內存,并且搜索時也會變得更快.