轉自博主 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的構造器http-equiv
的META標籤。 若是Beautiful Soup在文檔中發現編碼類型,它試着使用找到的類型轉換文檔。 可是,若是你明顯的指定一個編碼類型, 而且成功使用了編碼:這時它會忽略任何它在文檔中發現的編碼類型。chardet
庫,嗅探編碼,若是你安裝了這個庫。得 知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") |
結果也仍是不行。
關於此問題,後來網上找到了解釋:
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") |
便可。