Python+requests 爬取網站遇到中文亂碼怎麼辦?

分類: Python/Rubycss

    最近剛開始使用python來作爬蟲爬取相關數據,使用了python自帶的urllib和第三方庫requests,解析html使用了beautifulsoup以及lxml
    這裏說下lxml,lxml是python的一個html、xml解析庫,lxml使用XPath能快速,簡單的定位元素並獲取信息。下面進入正題
 
注:Python3處理亂碼很好解決了
好比;requests.get (url).text.encode('utf8','ignore')
      requests.get(url).content.decode('gbk','ignore')
    或者pycharm編譯器裏編碼設置成utf-8

1. 遇到的中文亂碼問題
1.1 簡單的開始
    使用requests來拔取網站內容十分方便,一個最簡單的代碼段只須要2-3行代碼就行。
 
點擊( 此處)摺疊或打開
  1. url = 'http//www.pythonscraping.com/'
  2. req = requests.get(url)
  3. print(req.text)
  4. tree = html.fromstring(req.text)
  5. print(tree.xpath("//h1[@class='title']/text()"))
    上面的代碼段起做用的也就3行(2,4,5)代碼就獲取到咱們想要的內容。固然還要導入一系列的包,好比說requests、lxml、html等。固然因爲http//www.pythonscraping.com/是英文網站,不存在中文亂碼問題。
1.2 麻煩的開始
    原本當時的想法是寫一些基礎模塊,方便以後開發的時候調用,減小重複性工做。爲了保證代碼在任何狀況下都不會出現bug,因此想着用一樣的代碼爬取中文網站獲取裏面的文字
    修改上面代碼中的兩行代碼:

點擊(此處)摺疊或打開 html

  1. url = 'http://sports.sina.com.cn/g/premierleague/index.shtml'
  2. print(tree.xpath("//span[@class='sec_blk_title']/text()"))
    運行程序能夠發現,在語句print(req.text)輸出的內容中,中文字體已是亂碼了。最後的結果輸出是['?????©è§\x86é?\x91', '??\x80?\x9c\x9f?\x9b\x9eé??']
2 亂碼解決辦法
2.1 試錯
    因爲以前爬取csdn上一個網頁沒有出現亂碼問題,可是在sina體育網站上出現了亂碼,因此當時覺得不是編碼問題,覺得是文檔壓縮問題。由於csdn獲取的頁面header裏沒有「Content-Encodings」屬性,可是sina體育獲取的頁面header有「Content-Encodings」屬性--「Content-Encoding: gzip」。
    在網上查看了多個相關問題的解決方案:
    1. http://stackoverflow.com/questions/3122145/zlib-error-error-3-while-decompressing-incorrect-header-check
    2. http://blog.csdn.net/pxf1234567/article/details/42006697
    3. http://blog.csdn.net/bytxl/article/details/21278249

總結:參考上述文獻,結果仍是沒有解決問題,可是就考慮是否是方向錯了。不過這部分工做也沒有白作,不少網站返回數據都會有壓縮問題,以後的工做中也能用上。

2.2 亂碼終極解決辦法
    後來查閱官方文檔中response-content相關內容,說明了Requests會自動解碼來自服務器的內容。Requests會基於HTTP頭部對響應的編碼做出有根據的推測,前提是響應文檔的HTTP headers裏面沒有相關字符集說明。官方文檔還說明了,若是你建立了本身的編碼,並使用 codecs 模塊進行註冊,你就能夠輕鬆地使用這個解碼器名稱做爲 r.encoding 的值, 而後由Requests來爲你處理編碼。(本身沒有使用codecs模塊,因此這裏不貼代碼了,不過按官方的說法使用codecs模塊是最簡單的一種方式。)
    另外一份官方文檔片斷明確說了reponse編碼處理方式:
        Requests遵循RFC標準,編碼使用ISO-8859-1 。
        只有當HTTP頭部不存在明確指定的字符集,而且 Content-Type 頭部字段包含 text 值之時, Requests纔不去猜想編碼方式。

    如今直接上實驗結果,在原始代碼中添加如下代碼片斷:

點擊(此處)摺疊或打開 python

  1. print(req.headers['content-type'])
  2. print(req.encoding)
  3. print(req.apparent_encoding)
  4. print(requests.utils.get_encodings_from_content(page_content.text))
輸出結果分別是:
    text/html
    ISO-8859-1#response內容的編碼
    utf-8#response headers裏設置的編碼
    ['utf-8']#response返回的html header標籤裏設置的編碼
    返回的內容是採用‘ISO-8859-1’,因此出現了亂碼,而實際上咱們應該採用‘utf-8’編碼
        
    總結:當response編碼是‘ISO-8859-1’,咱們應該首先查找response header設置的編碼;若是此編碼不存在,查看返回的Html的header設置的編碼,代碼以下:

點擊(此處)摺疊或打開 api

  1. if req.encoding == 'ISO-8859-1':
  2.     encodings = requests.utils.get_encodings_from_content(req.text)
  3.     if encodings:
  4.         encoding = encodings[0]
  5.     else:
  6.         encoding = req.apparent_encoding
  7. encode_content = req.content.decode(encoding, 'replace').encode('utf-8', 'replace')
    參考資料:     1. http://blog.csdn.net/a491057947/article/details/47292923     2. http://docs.python-requests.org/en/latest/user/quickstart/#response-content
相關文章
相關標籤/搜索