【問題解答】python解析網頁源代碼返回亂碼問題 | 在路上

【問題】

python解析網頁源代碼返回亂碼問題

代碼:

輸出:

直接print中文是可以的,注釋的中文也不會亂碼,就解析網頁亂碼 求有用解決方案!!

【問題解答】

從問題現象到問題本質,一點點幫你分析為何如何,以及如何解決問題

1.首先,根據之前的Python的IDE的經驗:

【整理】各種Python的IDE(集成開發環境)的總結和對比

從上述截圖,基本上,可以推測出來,其用的是:

【記錄】使用Python的IDE:Eclipse+PyDev

2.所以,為了完全重現其問題,專門去PyDev中建立了對應的項目。

代碼為:

# -*- coding: utf-8 -*- """Created on Oct 18, 2013@author: CLi"""from urllib import urlopendef getHtml(url): page = urlopen(url) html = page.read() page.close() return htmlif __name__ == "__main__": url = "http://www.sina.com.cn" html = getHtml(url) print html

然後,輸出,果然和其一樣:

3.對於此現象的原因:

(根據:詳解抓取網站,模擬登陸,抓取動態網頁的原理和實現(Python,C#等)的:【整理】關於HTML網頁源碼的字元編碼(charset)格式(GB2312,GBK,UTF-8,ISO8859-1等)的解釋)

先去確認了所要處理的網頁:

http://www.sina.com.cn/

中有:

<meta http-equiv="Content-type" content="text/html; charset=gb2312" />

(再根據:字元編碼簡明教程)

可知,此處的代碼處理中,如果需要解碼為Unicode,最好用GBK。

而此處得到的sina網頁的字元串,是GB2312

對應的,在Eclipse+PyDev中的console中輸出,結果卻亂碼了。

則可以確定:

Eclipse+PyDev的console中,所用字元編碼不是GB2312(也不是GBK或GB18030)

猜測:

估計是用的,相對常見的,UTF-8

4.但是不管其用什麼編碼,將Unicode的字元串輸出,則肯定應該是可以的:

5.為了驗證上面的PyDev的console是UTF-8的猜測,所以去用代碼:

# -*- coding: utf-8 -*- """Created on Oct 18, 2013@author: CLi"""from urllib import urlopendef getHtml(url): page = urlopen(url) html = page.read() page.close() #uniCodehtml = html.decode("GBK") #return uniCodehtml uniCodehtml = html.decode("GBK") utf8html = uniCodehtml.encode("UTF-8") return utf8htmlif __name__ == "__main__": url = "http://www.sina.com.cn" html = getHtml(url) print html

結果輸出果然是所預測的,正常的:

6.接下來,就很明顯了:

需要搞清楚,為何此處:

Eclipse+PyDev的Console中,

(不是我們之前所以為的,調用了Windows的cmd,以為是GBK編碼)

卻是UTF-8編碼

然後參考:

Printing Unicode in eclipse Pydev console and in Idle

而去看看:

結果在Eclipse的Window->Preferences中,找了半天,都沒有找到關於console的encoding方面的設置。

最後是在:

選擇你的PyDev項目->Run->Run Configuration-> Python Run ->選擇你當前的PyDev項目->Common->Encoding

才看到:

當前的,你的PyDev項目,運行期間,所用的console的編碼是utf-8

7.對應的,去改為GBK:

然後再點擊Run,結果,用之前,將Unicode故意轉為UTF-8的話,則輸出此時就是,所預料到的,亂碼了:

對應的,再去用,最原始的代碼,直接輸出(得到的GB2312的sina網頁),不做任何轉換的代碼:

8.由此,可以完全明白原因了:

(1)從sina獲得的html網頁,這個字元串,本身的字元編碼為:GB2312

(2)直接print輸出到,Eclipse+PyDev,中的console時,由於console默認是UTF-8編碼,所以:

將GB2312的sina的html網頁字元串輸出到UTF-8的Eclipse+PyDev的console中

必然導致亂碼。

而由於前面多次的嘗試可知,解決辦法有多種:

(1)代碼不改:

from urllib import urlopendef getHtml(url): page = urlopen(url) html = page.read() page.close() return htmlif __name__ == "__main__": url = "http://www.sina.com.cn" html = getHtml(url) print html

但是去改,Eclipse+PyDev的console的字元編碼,從UTF-8改為GBK(或GB2312,或GB18030):

選擇你的PyDev項目->Run->Run Configuration-> Python Run ->選擇你當前的PyDev項目->Common->Encoding->改為GBK

(2)不改Eclipse+PyDev的console的字元編碼,仍保持舊的UTF-8的配置,但是去改代碼:

from urllib import urlopendef getHtml(url): page = urlopen(url) html = page.read() page.close() uniCodehtml = html.decode("GBK") return uniCodehtmlif __name__ == "__main__": url = "http://www.sina.com.cn" html = getHtml(url) print html

即,獲得GB2312的html後,去decode為Unicode,然後直接輸出Unicode字元串到UTF-8的Eclipse+PyDev的console中,

則比如也是可以正常顯示無亂碼的

(內部會自動將輸出的Unicode轉換為當前console的UTF-8編碼的字元串的)

(3)基於上面那種方式,(不改Eclipse+PyDev的console的字元編碼,仍保持舊的UTF-8的配置),但是在轉換為Unicode後,再故意轉為輸出目標(此處的Eclipse+PyDev的console)的編碼,即UTF-8:

from urllib import urlopendef getHtml(url): page = urlopen(url) html = page.read() page.close() #uniCodehtml = html.decode("GBK") #return uniCodehtml uniCodehtml = html.decode("GBK") utf8html = uniCodehtml.encode("UTF-8") return utf8htmlif __name__ == "__main__": url = "http://www.sina.com.cn" html = getHtml(url) print html

也是可以保證輸出的網頁是正常的,中文不是亂碼。

關於返回的網頁是否要解壓縮

另外,有人提到的:

(以為此處獲得的網頁是壓縮的)

所以需要對於抓取回來的網頁進行解壓縮

此處實際結果證明了:

是不需要的。

其背後的原理和邏輯是:

(正常情況下)只有當你抓取網頁所提交的請求,包含了說你支持(即需要)返回壓縮的網頁

(人家伺服器)才返回對應的壓縮的網頁

詳見:

【總結】靜態網頁抓取,動態網頁抓取,模擬登陸的注意事項和心得

中的:「返回的html內容是二進位的亂碼」

進一步分析問題的現象和背後的本質

至此,上面的所有分析,還只是:

和解壓代碼無關,和字元串編碼有關

但是:

此處,才注意到,提問者提問所截的圖

看起來,還的確是:

列印出來的亂碼

像是二進位級別的字元串亂碼

而非之前所討論的,中文的亂碼

此刻,猜測問題最大的可能性是:

提問者,沒有給出背後相關的其所用的所有的代碼

估計其代碼,除了此處截圖給出的代碼之外

還是在別處,用到了對應的:

【總結】靜態網頁抓取,動態網頁抓取,模擬登陸的注意事項和心得

中的:「返回的html內容是二進位的亂碼」

所提到的:

添加了對應的頭信息,其中包含了:

Accept-Encoding設置了gzip,deflate

從而導致:

此處,返回的網頁,直接列印出現二進位那種的亂碼

(而不是字元編碼設置錯誤的,只會導致中文異常的那種亂碼)

所以:

  • 要麼是我上述推測錯了;
  • 要麼是,我推測是對的,而提問者,沒有給出錯誤現象背後的,相關的所有的代碼和背景條件
  • -> 導致上面耗費半天時間分析編碼錯誤導致中文亂碼,對於此問題來說,算是白費功夫了
  • -> 當然對於其他人不熟悉的此方面內容的,肯定還是有參考意義的
  • 無論哪種情況,此種,二進位亂碼

    的解決辦法是:

    核心相關代碼:

    #print "---before unzip, len(respHtml)=",len(respHtml);respInfo = resp.info(); # Server: nginx/1.0.8# Date: Sun, 08 Apr 2012 12:30:35 GMT# Content-Type: text/html# Transfer-Encoding: chunked# Connection: close# Vary: Accept-Encoding# ...# Content-Encoding: gzip # sometime, the request use gzip,deflate, but actually returned is un-gzip html# -> response info not include above "Content-Encoding: gzip"# eg: http://blog.sina.com.cn/s/comment_730793bf010144j7_3.html# -> so here only decode when it is indeed is gziped data #Content-Encoding: deflateif("Content-Encoding" in respInfo): if("gzip" == respInfo["Content-Encoding"]): respHtml = zlib.decompress(respHtml, 16+zlib.MAX_WBITS); elif("deflate" == respInfo["Content-Encoding"]): respHtml = zlib.decompress(respHtml, -zlib.MAX_WBITS);

    更詳細的解釋,參見:

    【總結】靜態網頁抓取,動態網頁抓取,模擬登陸的注意事項和心得

    中的:「返回的html內容是二進位的亂碼」

    對應的,很明顯,上面的核心代碼,

    本來就無需,無法,直接加入到,此處提問者所貼出的那段代碼的:

    因為:

    其所給出的代碼,根本就不應該存在此問題才對。

    更加,功能豐富的,用於抓取網頁的函數,其實我早就幫你們封裝好了,只是你們不知道,沒去用而已。

    感興趣的,自己去看:

    獲得Url地址的響應:getUrlResponse

    和:

    獲得Url返回的HTML網頁(源碼)內容:getUrlRespHtml

    即可。

    【總結】

    對於:

    Eclipse+PyDev的console,默認是UTF-8,而不是GBK

    導致讓不熟悉的人誤以為,輸出GBK(或Unicode)的字元串,

    會像輸出到GBK的Windows的cmd中一樣:

    中文不會亂碼

    如此細節:

  • 不熟悉的人,自然很難搞懂背後的邏輯:
  • 所以,對於,Python初學者,尤其是對字元編碼不是很清楚的人
  • -> 也包括對Python字元編碼清楚了,但是對於Eclipse不熟悉的人
  • -> 也包括,對於Eclipse很熟悉,但是對於PyDev中相關的console編碼不熟悉的人
  • 建議:

    1.對於字元編碼相關知識本身不熟悉,可參考:

    複雜教程:

    字元編碼詳解

    簡明教程:

    字元編碼簡明教程

    2.不熟悉Python的,自己去看:

    python初級教程:入門詳解

    3.對於初學者,還是建議先習慣和熟悉普通文件加上cmd去開發Python,熟悉了後,再去用各種IDE。

    詳細解釋見:

    總結:到底使用哪種環境去開發Python

    4.然後對於Python字元編碼方面,不了解的話,再去看:

    Python專題教程:字元串和字元編碼

    5.字元編碼書序了,Python也熟悉了,Python中的字元編碼也熟悉了之後,對於PyDev不熟悉,可參考:

    【整理】各種Python的IDE(集成開發環境)的總結和對比

    中的:

    【記錄】使用Python的IDE:Eclipse+PyDev

    最終:

    等所有相關知識都熟悉了後:

    你:

    愛用啥Python的IDE,就用啥;

    愛怎麼折騰IDE的配置,就怎麼折騰;

    愛怎麼寫代碼,去抓取網頁,處理網頁,就如何折騰,反正都可以搞定

    無論幹啥,都是:

    先要知道背景知識

    然後:

    折騰東西,出錯後,也才知道,錯誤的原因到底是啥,以及具體如何解決問題。


    推薦閱讀:

    解答2歲寶寶英語啟蒙的困惑
    捐精有什麼神秘之處,丁香醫生給你一一解答
    佛學問答類編06 李炳南老居士解答
    【香港旅遊】關於港澳通行證的若干問題解答,必收藏!
    佛學問答類編(凈土第十二).(十).李炳南老居士解答

    TAG:代碼 | 源代碼 | 亂碼 | 在路上 | 網頁 | 解析 | 問題 | 解答 |