python編碼錯誤和中文的亂碼問題,研究了整整兩天,查閱了很多資料,也走了一些彎路,我把經驗寫下,讓新手少走點彎路,本人技術較渣,有什么疏漏錯誤望大牛指正!
以下str表示文本字符,byte表示字節流。
py3只有str和byte,str只能encode,byte只能decode,不需要顯式地通過unicode這個“中間人”…py2就必須會經過unicode這個”中間人”….
主要講一下py2的編碼方式,因為現在用py2來造輪子的人挺多的,很多新手會因為中文亂碼的問題很頭疼,尤其是抓去網頁的數據的時候….
首先必須要知道輸入的str會被系統以什么方式去編碼,是utf-8還是gbk還是其他的編碼方式,用chartdet包可以來判斷。chardet包在win下要自行安裝!
import chardet
s=’大家好,我叫卓少!’
chardet.detect(s)
{'confidence': 0.99,?'encoding':?'GB2312'}
判斷出這個輸入將會以GB2312去編碼,用print 輸出也是GB2312編碼的中文。一般這種是在windows下py環境里的,GBK系列的編碼方式就是windows下默認的,Linux下的編碼方式一般是utf-8,輸出也一樣(這里講的都是中文的編碼方式,英文的默認是ascii…中文用ascii也編碼不了…才128個字符...)
上面這種輸入情況是自己敲鍵盤打進去的,還有一種輸入情況是你在網頁上爬取的str,這種你就要看看這個網站是什么編碼方式了,打開網頁的源代碼,上面可以看到chardet=’xxx’…一般現在基本都用的是utf-8編碼(utf-8是unicode中綜合性最好的編碼方式了,而且是包含了全世界各種語言字符的集合,大而全)。知道了網頁的編碼之后,我們分別來嘗試一下在可能會遇到的亂碼或者編碼錯誤的問題。
比如說我們來爬取一個網頁,就拿魚c的首頁來試水。先看看其前端的源碼,是utf-8的。寫個最簡單的爬取腳本。
import urllib2
url=’http://www.fishc.com’
res=urllib2.urlopen(url)
res=res.read()??#把抓取的網頁的utf-8數據流讀進去。
res=res.decode(‘utf-8’)?#由于數據流是utf-8,因此要把utf-8解碼成Unicode
#這里可以查看一下res的數據,可以發現有中文的地方就有/uxxx/uxxx啥的,這就是unicode字符…
#這也是編碼成其他形式的第一步,必須要先解碼變成unicode字符。再encode…
print res ???#print?這個命令有自動轉換成系統的”習慣編碼”(例如上面說的win下是GBK系列,linux下是utf-8系列),GBK編碼方式包含了所有中文,不會有亂碼。
我們來試試另一種種方法:(接著上面res=res.read()往后)
res?=res.encode(‘gbk’)?#直接在utf-8的時候編碼成gbk,由于win和linux系統默認編碼方式都是ascii?,肯定是顯示ascii cann’t decode…
怎么回事?utf-8編碼成gbk關ascii解碼啥事?
其實是這樣的,因為如果res這個字節流編碼不是unicode就直接encode的話python會自動用默認的編碼方式來decode成為unicode,剛才說過,py2編碼(encode)必須要先把原來的格式解碼(decode)成unicode,要經過這個”中間人”才能去編碼成其他格式…然而網頁的編碼方式是utf-8,用ascii方式來decode怎么可能不報錯呢…所以,我在網上找到了修改py默認編碼方式的方法(一般改成utf-8比較好):
在linux下:
python安裝目錄:/etc/python2.x/sitecustomize.py
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
try:
import apport_python_hook
except ImportError:
pass
else:
apport_python_hook.install()
如果在windows下:
可以在Python安裝目錄下的Lib/site-packages目錄中,新建一個sitecustomize.py文件(也可以建在其它地方,然后手工導入,建在這里,每次啟動Python的時候設置將自動生效),內容如下:
import sys
sys.setdefaultencoding('utf-8')?#set default encoding to utf-8
然后可以查看到改變已經生效
import sys
sys.getdefaultencoding()
'utf-8'
此時運行程序,如果仍然報告之前的錯誤,只需要顯示地設定輸出的編碼
print s.encode('utf-8')
就可以看到正確顯示。
本人親測有效!
改了默認編碼方式以后,只要網頁的編碼方式和修改的默認編碼方式相同,就可以直接encode,不需要decode這個步驟,因為這個步驟py會自動做好,代碼如下:
res =res.read()
res.encode(‘gbk’)?#在linux下可以這樣,不過經常會看到gbk cann’t encode \uxxx....這只是gbk儲存的字符集沒有utf-8多,所以用gbk去編碼unicode的話可能會出現”這個詞不懂”的現象,一般都是用utf-8來編碼gbk的,就不會”不懂”了,這個例子要是換成網站是gbk編碼的就好了(反過來就行),但是gbk的網站比較少,只是例子問題,了解原理就OK...
在win下直接print res就相當于encode(‘gbk’)了...
前面講的是用urllib2庫中的中文編碼問題,下面講一下requests庫中的中文編碼問題…
還是用那個例子
import requests
url=’http://www.fishc.com’
res=requests.get(url)
print res.content
這個用print res.content不會有任何問題,但是如果使用print res.text就有可能有問題...(如果你喜歡折騰的話就用res.text吧,改一個默認編碼方式就行)
這種情況輸入可能會有亂碼,因為res.text是unicode編碼…然后直接print res.text就會以默認的編碼方式輸出,這個默認的編碼方式是ISO-8859-1...應該是requests庫默認的,可以用res.encoding來查看其方式…一般都是'ISO-8859-1'
我們可以改變其默認的方式:
res.encoding=’utf-8’
改成utf-8之后再試試res.text就沒有亂碼了…
我看官方的文檔是說response.text每次都會去訪問response.encoding里的編碼方式。所以說py2真的很多地方沒有考慮到中文字符,連unicode字符集也是后面才加入的,一開始很長一段時間都是用ascii,誰讓這玩意是美國人發明的呢….
還好py3中有一些地方已經默認了是utf-8的方式,不然還得像py2一樣去修改…很多人一直在問新手應該學py2還是py3,我個人認為,py3對中文的支持是毋庸置疑的,論編程的方便是遠超py2的,但是因為年齡還比較短,py2具體有的很多包可能py3還不太完善,而且書籍也不多,所以如果想造輪子的話還是建議用py2,就是得多折騰些..不過未來肯定是py3的,這點是肯定的,如果新版本還比不上舊版本那做出來還有什么意義…所以說選擇還是看自己….