1. 程式人生 > >python爬蟲編碼問題

python爬蟲編碼問題

字符串 fff home 網上 360瀏覽器 .com pycha ctime 瀏覽器

爬蟲,新手很容易遇到編碼解碼方面的問題。在這裏總結下。

如果處理不好編碼解碼的問題,爬蟲輕則顯示亂碼,重則報錯UnicodeDecodeError: ‘xxxxxx‘ codec can‘t decode byte 0xc6 in position 1034: invalid continuation byte,這個xxx可能是 ascii utf8 gbk等。

大家一定要選個專門的時間學習下這方面,網上資源很多的。因為編碼 解碼歲不關程序邏輯功能大局 ,但幾乎每個程序中都會遇到這個東西,所以必須專門花時間學習實踐下以避免頻繁與麻煩。

1.先來兩個網址,選個gb2312的和一個utf8的網址。

utf8網站選擇 https://www.baidu.com 百度

gb2312的網站選擇 http://www.autohome.com.cn/beijing/#pvareaid=100519 汽車之家

url1=‘https://www.baidu.com‘
url2=‘http://www.autohome.com.cn/beijing/#pvareaid=100519‘
contentx=requests.get(url2).content

print unicode(contentx)
print contentx.encode(‘gbk‘)
print contentx.encode(‘utf8‘)

先說請求url1的情況


先上這六行代碼,如果是請求url1,那麽在py2.7.13上不會報錯,在py2.7.12上會報錯,但在pycharm的控制臺print的結果亂不亂碼我就不保證了,pycharm的設置中有project encoding選項,如果你設置的是utf8或者gbk,那麽第二個和第三個勢必會有一個是亂碼的顯示。同一個py代碼如果你在pychamr編輯器設置的是utf8,結果正常顯示,那麽在cmd運行python xx.py看到的結果那就必然會亂碼了。

技術分享

技術分享


上面說的是py2.7.13,如果你是2.7.12,那麽結果就不是這樣的了,在2.7.12中,上面六行代碼不會是顯示亂碼那麽簡單了,而是直接報錯


在2.7.12中運行下面這句
print requests.get(url1).content.encode(‘gbk‘)
或者運行unicode(requests.get(url1).content)
會提示

技術分享

因為直接從字符串轉另一個編碼格式格式,先會用默認的編碼decode解碼,再用指定的encode格式來編碼了。


可以在python腳本中運行這句話
import sys
print sys.getdefaultencoding()


2.7.13的

技術分享

2.7.12的

技術分享



py2.7.13的打印結果是utf8,而py2.7.12的打印結果卻是ascii,url1的網頁編碼是utf8,用ascii解碼會出錯。

要使py2.7.12中不報這個錯誤,那麽可以加入下面這句經典的代碼

技術分享

加入後,就不會出現 ascii codec cant decode 的提示了;如果不加入上面這句話,想把得到的內容encode成gbk格式的,可以按下面這麽做

print requests.get(url1).content.encode(‘gbk‘)把這個改成print requests.get(url1).content.decode(‘utf8‘).encode(‘gbk‘),這樣就不不會按照默認的編碼解碼了,就可以不需要上面的reload和setdefaultcoding。

import sys
print sys.getdefaultencoding()
reload(sys)
sys.setdefaultencoding(‘utf8‘)

這三行代碼不是萬金油,不能以為寫了這幾句就萬事大吉不會出編碼問題了,如果請求的是url2,汽車之家網頁是gbk格式的,
如果用print requests.get(url2).content.encode(‘utf8‘),那一樣會報錯從content字符串按照指定的utf8來解碼成unicode,那就會報錯了,這時候就需要sys.setdefaultencoding(‘gbk‘),而不是utf8了。

但你應該程序既要請求url1又要請求url2,那麽不管你怎麽指定默認的,如果不專門指定content的decode方式,勢必會有一個報錯。
那麽解決這個最需要的做的事情是
print requests.get(url1).content.decode(‘utf8‘).encode(‘xxxx‘)   xxx代表你想編碼的方式
print requests.get(url2).content.decode(‘gbk‘).encode(‘xxxx‘)

這樣做實用性就非常強了,不管你是2.7.12還是2.7.13,不管你寫不寫sys.setdefaultencoing和默認指定成什麽,都不會出現編碼問題了。





第二部分:如何知道網頁的編碼

使用360瀏覽器的右鍵很方便有一個編碼查看的功能,你們可以試試把gbk改成utf8或者utf8改成gbk,那麽瀏覽器會就出現亂碼了。用360瀏覽器點擊右鍵,99%的情況下就是網頁的編碼了,我是用360多年很少發現360出這種亂碼錯誤。

技術分享

除了瀏覽器查看外,還有一個方法是,右鍵點擊查看源代碼,下圖是百度的,可以看到用的是utf8,那麽把response的content用utf8 decode是不會出問題的,如果網頁源碼中charset是gb2312,用gbk deocde就可以。

技術分享


目前我做的事輿情分析,要爬取上萬個網站的新聞,用瀏覽器查看那肯定就不行了,進入什麽網頁都是未知的,如果是定向爬取,可以代碼指定用什麽格式decode

可以用下面這句話來獲取網頁編碼格式re.findall(‘<meta[\s\S]*?charset="?(.*?)"‘,content,re.IGNORECASE)[0]


之前同事介紹了一個編碼獲取的包,名字叫chardet,用法是chardet.detect(content),這個方法非常準確,但是缺點太大了,長時間占用cpu計算,cpu使用率太高,整個爬蟲速度被扯下來了。當頁面內容比較大的時候,用chardet來,甚至探測一個編碼方式需要15秒之久,這方法不好。


為了看到chardet到底在幹什麽要那麽久,把日誌打印出來。
代碼貼出來,對這個包感興趣的可以看看。


#coding=utf8
import requests
import chardet,logging
logger=logging.getLogger(‘‘)
logger.setLevel(logging.DEBUG)
stream_handler=logging.StreamHandler()
stream_handler.setLevel(logging.DEBUG)
fmt=logging.Formatter(%(asctime)s - %(name)s - %(levelname)s - %(message)s)
stream_handler.setFormatter(fmt)
logger.addHandler(stream_handler)

url1=https://www.baidu.com
url2=http://www.autohome.com.cn/beijing/#pvareaid=100519
contentx=requests.get(url2).content
bianma=chardet.detect(contentx)
print bianma

技術分享

看了此篇後,應該不至於遇到編碼問題了。



python爬蟲編碼問題