【已解決】python中文字符亂碼(GB2312,GBK,GB18030相關的問題)


 

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:
  • 可以通過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= gbkfromEncoding= 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")
  即可。
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM