http://againinput4.blog.163.com/blog/static/1727994912011111011432810/
【已解決】python中文字符亂碼(GB2312,GBK,GB18030相關的問題)
【背景】
在玩wordpress的一個博客搬家工具BlogMover,其包含幾個python腳本,其中有個是163博客搬家用的163-blog-mover.py,實現抓取網易博客的日志,然后導出xml。
但是其工具現在(2011-12-10)已經失效了。經過自己一點修改后,可以實現獲得文章標題了。
用法還是原先的用法:
163-blog-mover.py -fhttp://againinput4.blog.163.com/blog/static/172799491201111893853485/ |
獲得的此篇日志的標題:
【已解決】允許hi-baidu-mover_v2.py出錯:UnboundLocalError: local variable 'linkNode' referenced before assignment
中包含中文,在將該標題打印出來到log中后,卻發現中文部分顯示亂碼:
????·??????????íhi-baidu-mover_v2.py???í??UnboundLocalError: local variable 'linkNode' referenced before assignment
所以想要去除亂碼,正確顯示中文。
【解決過程】
1. 本身那段文字,是從網頁中抓取的,關於該日志的中文編碼,也已經從網頁中的:
<metahttp-equiv="content-type"content="text/html;charset=gbk"/>
看出來是GBK了。
而python中,原先默認編碼發現是ascii,后來去通過:
reload(sys)
sys.setdefaultencoding('utf-8')
去將默認編碼設置為utf-8,但是結果輸出還是亂碼。
2.后來網上找了一堆帖子, 包括最后這個:
http://www.tangc.com.cn/view_article_117.html
去嘗試先對其解碼,再編碼:
string.decode('GBK').encode(utf-8')
結果還是亂碼:
隆戮虜驢路脰陸芒戮枚隆驢脭脢脨鉚hi-baidu-mover_v2.py魯枚麓鉚攏潞UnboundLocalError: local variable 'linkNode' referenced before assignment
而又去試了試其他的,比如:
temp.string.strip().decode('GBK').encode('mcbs)
輸出也是亂碼,和不轉換之前是一樣的。
總之,還是無法及解決亂碼問題。
3.后來,在學習Beautiful Soup的時候:
http://www.crummy.com/software/BeautifulSoup/documentation.zh.html#contents
Beautiful Soup 會按順序嘗試不同的編碼將你的文檔轉換為Unicode:
|
得知Beautiful Soup默認已經可以通過你所給的鏈接中的HTML源碼中的meta的http-equiv頭,去解析charset,已經可以知道網頁的編碼是上面所顯示的GBK了,而且自動會去以該編碼獲得網頁內容,然后自動輸出為utf-8的unicode了。
所以python中去:
print "###originalEncoding=",soup.originalEncoding,"declaredHTMLEncoding=",soup.declaredHTMLEncoding,"fromEncoding=",soup.fromEncoding |
###originalEncoding= windows-1252 declaredHTMLEncoding= gbkfromEncoding= None |
也因此,自己手動嘗試,在open URL的時候,給Beautiful Soup傳遞GBK參數,即:
page = urllib2.build_opener().open(req).read() soup = BeautifulSoup(page, fromEncoding="GBK") |
關於此問題,后來網上找到了解釋:
http://groups.google.com/group/python-cn/browse_thread/thread/cb418ce811563524
請注意 gb2312 不是 “gb2312”,凡 gb2312 的請換成 gb18030. 微軟將 gb2312 和 gbk 映射為 gb18030,方便了一些人,也迷惑了一些人。 |
即,實際上該網頁是GB18030的編碼,所以按照這里:
http://blog.csdn.net/fanfan19881119/article/details/6789366
(原始出處為:http://leeon.me/a/beautifulsoup-chinese-page-resolve)
的方法,傳遞GB18030給fromEncoding,才可以:
page = urllib2.build_opener().open(req).read() soup = BeautifulSoup(page, fromEncoding="GB18030") |
最近需要寫一個python的RSS抓取解析程序,使用了feed parser。但是對於百度新聞的RSS,其編碼方式為gb2312,feed parser探測出來的編碼卻是windows-1252,結果中文內容都是一堆亂碼。 問題在於,並不是feedparser不能識別出gb2312編碼,而是國人們往往將gb2312與gbk編碼等同,某些已經使用了gbk編碼里的字符的,仍然聲稱內容為gb2312編碼。feedparser對gb2312編碼嚴格遵循gb2312字符集范圍,當探測到超出這一范圍的字符,便將編碼回退到windows-1252。由於百度的RSS實際使用的應該是gbk編碼,里面含有超出gb2312范圍的字符,於是feedparser便擅自決定了將編碼退回windows-1252,導致了中文亂碼的現象。 |
【總結】
以后用python的Beautiful Soup去解析中文網頁的話:
1.如果本身網頁的編碼自己標稱的,和本身其中文字符所用編碼完全符合的話,即沒有部分字符超出了其所標稱的編碼,比如標稱為GBK,網頁所有的內容,都的確是GBK編碼,沒有超出的其他字符(比如屬於GB18030的編碼),那么,是可以通過:
page = urllib2.urlopen(url) soup = BeautifulSoup(page) #此處不需要傳遞參數,BeautifulSoup也完全可以自己去解析網頁內容所使用的編碼 print soup.originalEncoding |
而得到真實的網頁的編碼的。
2.討論中文亂碼問題之前,先解釋關於中文字符編碼:
時間上的發展先后是,GB2312,GBK,GB18030,編碼技術上都是兼容的。
從所包含的中文字符個數來說,算是:GB2312 < GBK < GB18030,也因此,才可能會出現上面所說的,標稱GB2312的,部分字符用到了GBK里面的,或者是標稱GBK的,部分字符用到了GB18030里面的,所以被人家編碼工具解析錯誤,退回認為編碼是最基本的windows-2152了。
而我這里的情況就是屬於后者,網易博客網頁中,自己聲稱是GBK,但是很多中文字符用的是GB18030。
總的說,現在實際情況是,由於編寫網頁代碼的人所用的字符編碼所不同,以及自己在網頁中聲稱的編碼和實際自己網頁所用的編碼不同,導致了中文網頁出現亂碼。所以,要先搞懂這些中文字符編碼之間關系,以及歷史上的邏輯前后關系,才可能解決這類問題。
關於中文字符編碼,更多詳細解釋請參考這里:
中文字符編碼標准+Unicode+Code Page
http://bbs.chinaunix.net/thread-3610023-1-1.html
所以:
(1)如果是網頁標稱為GB2312,但是部分字符用到了GBK的了,那么解決辦法就是在調用BeautifulSoup,傳遞參數fromEncoding="GBK",即:
page = urllib2.build_opener().open(req).read() soup = BeautifulSoup(page, fromEncoding="GBK") |
(2)如果是網頁標稱為GBK,但是部分字符用到了GB18030的了,那么解決辦法就是在調用BeautifulSoup,傳遞參數fromEncoding="GB18030",即:
page = urllib2.build_opener().open(req).read() soup = BeautifulSoup(page, fromEncoding="GB18030") |
(3)實際上由於GB18030從字符數上都涵蓋了GB2312和GBK,所以如果是上述兩種任意情況,即只要是中文字符出現亂碼,不管是標稱GB2312中用到了GBK,還是標稱GBK中用到了GB18030,那么都直接傳遞GB18030,也是可以的,即:
soup = BeautifulSoup(page, fromEncoding="GB18030") |