目次
はじめに
Pythonでスクレイピングをして、画像ダウンロードのテストをしていました。
その中で、特定のサイトからダウンロードしてきた画像だけが全て壊れてしまう現象が発生していました。

長い間放置していたのですが、UdemyでAWSの教材をみている時にふと天啓が降ってきました。
画像が壊れてしまう原因は、gzipじゃないだろうか?
gzipとは
HTTP 1.1にはデータを圧縮し転送量を減らす機能があるが、gzipはその際の圧縮フォーマットの一つとしても使われている。
出典 - WIKI
https://ja.wikipedia.org/wiki/Gzip
サーバーからクライアントへHTMLやCSSなどの生データを送るより、圧縮した方が早く届きます(容量が少ないので。
その為の圧縮形式の一つがgzipです。
Choromeなどのデベロッパーツールを使って、ネットワークを見てもらうと確認することができます。
例えばYahooなどもgzipでHTMLデータを送信しています。

最近だとどこのサーバーでも使われているのではないでしょうか?
ところで、このgzipですが画像などには効果が薄いので、使う機会はほとんど無いと思います。
そもそもJPEGなどは予め圧縮されてますしねー。
gzipでダウンロード画像が壊れる
さて上で説明した通り、画像にgzipをかけるのは効果が薄いです。
しかし、知ってか知らずか該当のサイトは、画像をgzipかけてました。

あちゃー(ノ▽`;)
確かに予兆はあったんですよね。
ブラウザで直接ダウンロードしてくるのと容量に差があったんですよね。
おそらくPythonでダウンロードしてくると、gzipのファイルをダウンロードしていたんでしょうね。
拡張子が.jpgや.pngなので壊れてた扱いなのかなと。
対応
ぐだぐだと話をしてきましたが、対応方法になります。
shutil.copyfileobj の前に res.raw.decode_content = True を設定しましょう。
これで解凍した画像を保存することができます。
path = r'/Users/admin/Public/project/MyImages/image'
all_images = [
'https://i1.wp.com/s1.wp.com/wp-content/themes/h4/landing/marketing/pages/hp-jan-2020-v2/media/desktop/desktop-website-v2-2x.jpg?ssl=1',
'https://i1.wp.com/s1.wp.com/wp-content/themes/h4/landing/marketing/pages/hp-jan-2020-v2/media/desktop/theme-coutoire-2x.jpg?ssl=1',
]
try:
for index, image in enumerate(all_images):
filename = "image_" + str(index) + ".jpg"
local_path = os.path.join(path, filename)
res = requests.get(image, stream=True)
with open(local_path, "wb") as file:
res.raw.decode_content = True
shutil.copyfileobj(res.raw, file)
except Exception as e:
print(e)
print(str(index) + "番目の画像ダウンロードに失敗しました")
print("画像のURL" + image)
さいごに
ぐだぐだと偉そうに記事を書きましたが、かなり薄い知識で記事にしています。
gzipの他にbrotliの場合もあるので、デベロッパーツールで都度確認してもらえたら良いと思います。
検討外れなところや、改善出来そうなところがあったら教えてください。
今日はこの辺でー