python字元編碼轉換經驗

菜鳥學python(一)

最近開始學慣用python抓取網頁,遇到了字元編碼錯亂的問題,頭疼不已。情況是這樣的:

我下載了東方財富網的股票列表頁面http://quote.eastmoney.com/stocklist.html,並想從中提取股票簡稱和股票代碼存入一個txt文件,以備將來使用,但是,在提取網頁內容時,提取的中文內容是一堆亂碼。我使用的是python34,requests和BeautifulSoup,代碼如下:

#coding:utf8

import requests as rq

from bs4 import BeautifulSoup as bs

url=quote.eastmoney.com/sto

hd={User-Agent:Mozilla/5.0}

#下載網頁

resp=rq.get(url,headers=hd)

#解析網頁

soup=bs(resp.text,html.parser)

print(resp.text)

運行結果(因為內容很多,只選取其一段,能表明遇到問題的情況)為:

......

http://quote.eastmoney.com/sz300590.html">ò??aí¨D?(300590)

http://quote.eastmoney.com/sz300591.html">íòà??í(300591)

......

我首先想到是字元編碼,一查看下載網頁的編碼為『gb2312』,如果要正常顯示,必須轉換成『utf8』(因為我的python默認的字元是『utf8』)。我用必應搜索了一下『python字元編碼轉換』的解決方案,有很多條目,基本上都是用encode和decode方法進行字元編碼轉換的經驗,我也照此進行嘗試,結果還是不行。經過多次失敗,我逐漸意識到,大家討論的事不在同一個頻道上。

我的目標是,將編碼為『gb2312』的網頁「翻譯」成編碼為『utf8』的網頁。之所以要用「翻譯」這個表述,主要是要表達我的實際意思,比如,假設「中文」這個詞的』gb2312『編碼是』xaa『,而其』utf8『編碼是』0bb『(為敘述方便,編碼皆為瞎編,見諒!),如果獲得』中文『這個詞的』gb2312『編碼,要想將它在』utf8『的環境下正常顯示(或理解)為』中文『,必須有一種方法將它的』gb2312『編碼』xaa『相應變換成utf8『編碼』0bb『,這就是「翻譯」的含義。

而encode和decode方法無法完成上述「翻譯」任務,它們能做工作是「轉換」,關於』轉換『的原理,我是這樣理解的,假設「中文」這個詞的』gb2312『編碼是』xaa『,而其』utf8『編碼是』0bb『,將「中文」這個詞的』gb2312『編碼』轉換『為』utf8『編碼,得到的』utf8『編碼仍然是』xaa『,只不過是以』utf8『編碼方式來讀取或顯示,其結果是什麼就不得而知了,且看如下測試:

>>> a=中文

>>> type(a)

<class str>

>>> b=a.encode(gb2312)

>>> type(b)

<class bytes>

>>> print(a)

中文

>>> print(b)

bxd6xd0xcexc4

>>> c=b.decode(utf8)

Traceback (most recent call last):

File "<pyshell#7>", line 1, in <module>

c=b.decode(utf8)

UnicodeDecodeError: utf-8 codec cant decode byte 0xd6 in position 0: invalid continuation byte

>>>

以上測試顯示,encode和decode方法無法實現編碼「翻譯」

那麼,如何才能達成翻譯的目標的呢?在對encode和decode絕望之後,我不得不別另尋他徑。有沒有可能在獲取網頁內容時實現編碼』翻譯』呢?我想到了requests,requests對象有沒有這樣的屬性或方法在提取網頁內容時實現『翻譯』呢?我又用必應搜索了一上,還真發現了requests對象的encoding屬性可能是解決問題的關鍵,為此,我做了一個測試:

#coding:utf8

import requests as rq

from bs4 import BeautifulSoup as bs

url=quote.eastmoney.com/sto

hd={User-Agent:Mozilla/5.0}

#下載網頁

resp=rq.get(url,headers=hd)

print(resp.encoding)

結果是:

ISO-8859-1

這是什麼鬼?我思考一下,覺得應該是:在默認情況下,requests將獲取的網頁看作是『ISO-8859-1』編碼(我也不知道這是什麼編碼!)的,並照此『翻譯』成『utf8』編碼。而實際上,獲取的網頁是『gb2312』編碼,應按照將『gb2312』編碼翻譯成『utf8』編碼方式進行翻譯。所以,出錯在所難免。如果告訴requests獲取的網頁編碼是『gb2312』編碼,它會不會正確完成任務呢?我又做了如下測試:

#coding:utf8

import requests as rq

from bs4 import BeautifulSoup as bs

url=quote.eastmoney.com/sto

hd={User-Agent:Mozilla/5.0}

#下載網頁

resp=rq.get(url,headers=hd)

print(resp.encoding)

resp.encoding=gb2312

print(resp.encoding)

結果是:

ISO-8859-1

gb2312

好了,requests已經知道獲取的網頁的編碼是『gb2312』了,再繼續解碼列印:

#解析網頁

soup=bs(resp.text,html.parser)

print(resp.text)

結果(仍然是截取一段,意思一下!)如下:

......

quote.eastmoney.com/sz3">移為通信(300590)

quote.eastmoney.com/sz3">萬里馬(300591)

.....

成功了!!!

總結如下:

  1. 要區分『翻譯』和『轉換』的概念。現實中,你想要的是『翻譯』,獲得的建議卻是『轉換』,結果就是『差之毫釐,謬以千里』。
  2. encode和decode方法的作用是『轉換』,對『翻譯』毫無用處。
  3. requests可以實現『翻譯』,前提是要正確指明要翻譯的網頁的編碼。

本人是一名python菜鳥,在編碼轉換中幾經煎熬,獲得前述成 果,希望對你有所幫助!錯謬之處,歡迎指正!

版權聲明:本文的著作權屬於本人,歡迎轉載,但應註明出處。

推薦閱讀:

Android開發學習應該先學什麼?
[2] 編寫第一個C語言程序
[4] 函數
[1] 搭建編程的環境
[6] 分支、循環與遞歸

TAG:Python | 計算機 | 編程入門 |