Python2的中文編碼問題

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的,這點是肯定的,如果新版本還比不上舊版本那做出來還有什么意義…所以說選擇還是看自己….

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容