gzip化されたhttpレスポンスを解凍する

Tips

経緯

WEBスクレイピングする際に、HTTP取得するときに

import urllib.request
## URLからHTMLファイルを取得する
def getHttp(_url):
  with urllib.request.urlopen(_url) as res:
    return res.read().decode("utf-8")

こんな感じで取得してるが、なんかたまにutf-8でデコードできないものが返ってくるときがあった。

UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position 1: invalid start byte

 

原因

戻ってきたHTMLがgzipで圧縮されてた。

b'\x1f\x8b\x08\

で始まるものはgzip

gzipを解凍せずにそのままutf-8でデコードしようとしてたのでデコードエラーを吐いていた。

 

解決策

戻ってきたHTMLを解凍してからデコードするようにする。

import urllib.request
import gzip
## URLからGZIP化されているHTMLファイルを取得する
def getGzipHttp(_url):
  with urllib.request.urlopen(_url) as res:
    dec = gzip.GzipFile(fileobj=res)
    return dec.read().decode("utf-8")

本当は戻ってきたHTMLがgzipであるかどうかを調べて、圧縮されてたら解凍する、

みたいな処理にすると綺麗だけど、突貫工事でまずはこんな感じ。

 

改良版

なんならデコードも自動で判別してくれたらよくね?

と思って改良版を作成。

import urllib.request
import gzip
import chardet

def getHttpEX(_url):
  with urllib.request.urlopen(_url) as res:
    dec = None
    data = None
    
    dec = gzip.GzipFile(fileobj=res)
      
    try:
      data = dec.read()
    except Exception as e:
      data = res.read()
    enc = chardet.detect(data)['encoding']
    
    return data.decode(enc)

これでgzipだろうがShift-jisだろうがちゃんとデコードしてくれる・・・はず

コメント

タイトルとURLをコピーしました