読者です 読者をやめる 読者になる 読者になる

試される大地から

furaiboが送る技術ブログ。プログラミングのTipsなど書いていきます。

Pythonの「'ascii' codec can't decode byte 0x8b」エラーの怪を探れ!!


夜分遅くにこんばんわ。furaiboでございます。現在、Webページ内の画像をすべて取得するPythonツールを書いておりますが、あるWebページからHTMLを文字列として取得し、この文字列の文字コードををutf-8に変換しようとした所、題名のような


'ascii' codec can't decode byte 0x8b


というエラーメッセージに遭遇いたしました。そして、どのような文字コードを試してみても変換できず、取得したHTMLファイルの文字列を出力しても意味の分からない記号列、そして文字コードも判定不可という八方塞がりの状態になってしまいました。



しかし、これの原因は非常に単純なことだったんです。



エラーの解決法


結論から言いますとサーバから送信されてきたHTTPレスポンスのボディ部分がgzip形式として圧縮されていることが原因でした。


つまり、gzipとなっている文字列を解凍する必要があります。


具体的には以下のようにすればOKです。


#!/usr/bin/python

# パッケージのインポート
import urllib2
import StringIO
import gzip

# 変数
url  = "WebページのURL"		# WebページのURL
html = ""			# リンク先URLでのHTMLの内容

# HTTPリクエスト
req = urllib2.Request(url, headers={'User-Agent' : "Magic Browser"})
con = urllib2.urlopen(req)	# 指定のURLをオープン
html = con.read()		# HTMLページの内容を取得
		
# body部分がgzip化されている場合の処理
if con.info().get('Content-Encoding') == 'gzip':
	data = StringIO.StringIO( html )
	gzipper = gzip.GzipFile(fileobj=data)
	html = gzipper.read()

# 出力テスト
print html


これで、送信されてきたHTMLボディ部分がgzip化されていても問題なく中身を取得出来ます。苦戦していましたが、これでやっといろんなページのHTMLを取得できそうです。



日本語のページだと文字コードに関連した記述しかなく、gzipによる圧縮が原因であることについて触れているページは見つかりませんでした。以上の記述はPythonの公式ドキュメントとStackOverflowを参考としています。




参考ページは以下。


python - urllib2 opener providing wrong charset - Stack Overflow(英語)

python - Convert gzipped data fetched by urllib2 to HTML - Stack Overflow(英語)