python中文字符亂碼(GB2312,GBK,GB18030相關的問題)

轉自博主 crifan http://againinput4.blog.163.com/blog/static/1727994912011111011432810/  html

在玩wordpress的一個博客搬家工具BlogMover,其包含幾個python腳本,其中有個是163博客搬家用的163-blog-mover.py,實現抓取網易博客的日誌,而後導出xml。python

可是其工具如今(2011-12-10)已經失效了。通過本身一點修改後,能夠實現得到文章標題了。windows

用法仍是原先的用法:wordpress

 

 163-blog-mover.py -f http://againinput4.blog.163.com/blog/static/172799491201111893853485/

得到的此篇日誌的標題:工具

【已解決】容許hi-baidu-mover_v2.py出錯:UnboundLocalError: local variable 'linkNode' referenced before assignment學習

中包含中文,在將該標題打印出來到log中後,卻發現中文部分顯示亂碼:ui

????·??????????íhi-baidu-mover_v2.py???í??UnboundLocalError: local variable 'linkNode' referenced before assignmentgoogle

因此想要去除亂碼,正確顯示中文。編碼

【解決過程】url

1. 自己那段文字,是從網頁中抓取的,關於該日誌的中文編碼,也已經從網頁中的:

    <meta http-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:

  • 能夠經過fromEncoding參數傳遞編碼類型給soup的構造器
  • 經過文檔自己找到編碼類型:例如XML的聲明或者HTML文檔http-equiv的META標籤。 若是Beautiful Soup在文檔中發現編碼類型,它試着使用找到的類型轉換文檔。 可是,若是你明顯的指定一個編碼類型, 而且成功使用了編碼:這時它會忽略任何它在文檔中發現的編碼類型。
  • 經過嗅探文件開頭的一下數據,判斷編碼。若是編碼類型能夠被檢測到, 它將是這些中的一個:UTF-*編碼,EBCDIC或者ASCII。
  • 經過chardet庫,嗅探編碼,若是你安裝了這個庫。
  • UTF-8
  • Windows-1252

  得 知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= gbk fromEncoding= None

   了, 可是也仍是很奇怪,爲什麼原先網頁的編碼,HTML中聲明的是GBK,而Beautiful Soup解析出來的網頁原始編碼originalEncoding是windows-1252呢,二者不同(我另外試了別的一個百度的網 頁,declaredHTMLEncoding是GBK,originalEncoding也是declaredHTMLEncoding)。

也所以,本身手動嘗試,在open URL的時候,給Beautiful Soup傳遞GBK參數,即:

 

 page = urllib2.build_opener().open(req).read()
soup = BeautifulSoup(page, fromEncoding="GBK")

 結果也仍是不行。

關於此問題,後來網上找到了解釋:
Beautiful Soup gb2312亂碼問題

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")

   而其中,也解釋了,爲什麼HTML標稱的GBK的編碼,可是卻解析出來爲windows-1252了:

 

 最近須要寫一個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")

  便可。

相關文章
相關標籤/搜索