分類: Python/Ruby
最近剛開始使用python來做爬蟲爬取相關數據,使用了python自帶的urllib和第三方庫requests,解析html使用了beautifulsoup以及lxml
這里說下lxml,lxml是python的一個html、xml解析庫,lxml使用XPath能快速,簡單的定位元素並獲取信息。下面進入正題
這里說下lxml,lxml是python的一個html、xml解析庫,lxml使用XPath能快速,簡單的定位元素並獲取信息。下面進入正題
注:Python3處理亂碼很好解決了
比如;requests.get
(url).text.encode('utf8','ignore')
requests.get(url).content.decode('gbk','ignore')
或者pycharm編譯器里編碼設置成utf-8
1. 遇到的中文亂碼問題
1.1 簡單的開始
使用requests來拔取網站內容十分方便,一個最簡單的代碼段只需要2-3行代碼就行。
點擊(
此處)折疊或打開
- url = 'http//www.pythonscraping.com/'
- req = requests.get(url)
- print(req.text)
- tree = html.fromstring(req.text)
- print(tree.xpath("//h1[@class='title']/text()"))
1.2 麻煩的開始
本來當時的想法是寫一些基礎模塊,方便之后開發的時候調用,減少重復性工作。為了保證代碼在任何情況下都不會出現bug,所以想着用同樣的代碼爬取中文網站獲取里面的文字
修改上面代碼中的兩行代碼:
點擊(此處)折疊或打開
- url = 'http://sports.sina.com.cn/g/premierleague/index.shtml'
- print(tree.xpath("//span[@class='sec_blk_title']/text()"))
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設置的編碼,代碼如下:
點擊(此處)折疊或打開
- 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
