経緯
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だろうがちゃんとデコードしてくれる・・・はず
コメント