最近剛開始使用python來作爬蟲爬取相關數據,使用了python自帶的urllib和第三方庫requests,解析html使用了beautifulsoup以及lxml
這裏說下lxml,lxml是python的一個html、xml解析庫,lxml使用XPath能快速,簡單的定位元素並獲取信息。下面進入正題
- url = 'http//www.pythonscraping.com/'
- req = requests.get(url)
- print(req.text)
- tree = html.fromstring(req.text)
- print(tree.xpath("//h1[@class='title']/text()"))
上面的代碼段起做用的也就3行(2,4,5)代碼就獲取到咱們想要的內容。固然還要導入一系列的包,好比說requests、lxml、html等。固然因爲http//www.pythonscraping.com/是英文網站,不存在中文亂碼問題。
1.2 麻煩的開始
原本當時的想法是寫一些基礎模塊,方便以後開發的時候調用,減小重複性工做。爲了保證代碼在任何狀況下都不會出現bug,因此想着用一樣的代碼爬取中文網站獲取裏面的文字
修改上面代碼中的兩行代碼:
- url = 'http://sports.sina.com.cn/g/premierleague/index.shtml'
- print(tree.xpath("//span[@class='sec_blk_title']/text()"))
運行程序能夠發現,在語句print(req.text)輸出的內容中,中文字體已是亂碼了。最後的結果輸出是['?????©è§\x86é?\x91', '??\x80?\x9c\x9f?\x9b\x9eé??']
2 亂碼解決辦法
2.1 試錯
因爲以前爬取csdn上一個網頁沒有出現亂碼問題,可是在sina體育網站上出現了亂碼,因此當時覺得不是編碼問題,覺得是文檔壓縮問題。由於csdn獲取的頁面header裏沒有「Content-Encodings」屬性,可是sina體育獲取的頁面header有「Content-Encodings」屬性--「Content-Encoding: gzip」。
在網上查看了多個相關問題的解決方案:
1. http://stackoverflow.com/questions/3122145/zlib-error-error-3-while-decompressing-incorrect-header-check
2. http://blog.csdn.net/pxf1234567/article/details/42006697
3. http://blog.csdn.net/bytxl/article/details/21278249
總結:參考上述文獻,結果仍是沒有解決問題,可是就考慮是否是方向錯了。不過這部分工做也沒有白作,不少網站返回數據都會有壓縮問題,以後的工做中也能用上。
2.2 亂碼終極解決辦法
後來查閱官方文檔中response-content相關內容,說明了Requests會自動解碼來自服務器的內容。Requests會基於HTTP頭部對響應的編碼做出有根據的推測,前提是響應文檔的HTTP headers裏面沒有相關字符集說明。官方文檔還說明了,若是你建立了本身的編碼,並使用
codecs 模塊進行註冊,你就能夠輕鬆地使用這個解碼器名稱做爲 r.encoding 的值, 而後由Requests來爲你處理編碼。(本身沒有使用codecs模塊,因此這裏不貼代碼了,不過按官方的說法使用codecs模塊是最簡單的一種方式。)
另外一份官方文檔片斷明確說了reponse編碼處理方式:
Requests遵循RFC標準,編碼使用ISO-8859-1 。
只有當HTTP頭部不存在明確指定的字符集,而且 Content-Type 頭部字段包含 text 值之時, Requests纔不去猜想編碼方式。
如今直接上實驗結果,在原始代碼中添加如下代碼片斷:
- print(req.headers['content-type'])
- print(req.encoding)
- print(req.apparent_encoding)
- print(requests.utils.get_encodings_from_content(page_content.text))
輸出結果分別是:
text/html
ISO-8859-1#response內容的編碼
utf-8#response headers裏設置的編碼
['utf-8']#response返回的html header標籤裏設置的編碼
返回的內容是採用‘ISO-8859-1’,因此出現了亂碼,而實際上咱們應該採用‘utf-8’編碼
總結:當response編碼是‘ISO-8859-1’,咱們應該首先查找response header設置的編碼;若是此編碼不存在,查看返回的Html的header設置的編碼,代碼以下:
點擊(此處)摺疊或打開 api
- if req.encoding == 'ISO-8859-1':
- encodings = requests.utils.get_encodings_from_content(req.text)
- if encodings:
- encoding = encodings[0]
- else:
- encoding = req.apparent_encoding
- encode_content = req.content.decode(encoding, 'replace').encode('utf-8', 'replace')
參考資料: 1. http://blog.csdn.net/a491057947/article/details/47292923 2. http://docs.python-requests.org/en/latest/user/quickstart/#response-content