【Python】requestsを使った画像ファイルのダウンロードの失敗事例

画像ファイルのダウンロードの失敗事例です。明らかに画像取得目的の”User-Agent”でもって、数十回とリクエストしたところ、リクエストとは異なる画像ファイルが毎回送信されてくるようになりました。そして、”User-Agent”を設定し直しても続くのです。

しかし、1時間経過した後、再度正しい”User-Agent”でリクエストをしたところ、今度はダウンロードできるようになりました。

こういった現象は、サーバにアクセスが集中していると起こるようですが、アンチスクレイピングの可能性も捨てきれません。原因はともかく、確実にダウンロードができるようにする必要があります。

Pythonで画像ファイルを安全にダウンロードする簡単なサンプル

下のサンプルでは、requestsパッケージを使って、getリクストをサーバに送り画像ファイルを落としています。もちろんイメージファイルだけではなく、xlsxやmp4等の任意のファイルのダウロードが可能です。

安全にリクエストするために何をしたかというと、ブラウザからアクセスしていると分かるように設定しただけです。設定しているのは、下のサンプルコードのheaderになります。下のheaderは、Windows10からChromeでアクセスしていると仮定しています。

import requests


header = {
    "Accept": "*/*",        # MIMEタイプ
    "Accept-Encoding": "gzip, deflate",     # 通信の圧縮形式
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "\
                  "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36"
}

with requests.get("https://hogehoge.com/foo.jpg", headers=header, stream=True) as res:
    with open("get.jpg", "wb") as f:
        for chunk in res.iter_content(chunk_size=1024):
            if chunk:
                f.write(chunk)

requestsにヘッダーを設定しない場合に起こること

もし、下のようにheaderを設定しないでリクストすると、”User-Agent” が ‘python-requests/2.25.1’ になります。これが、疑われる元になります。

requests.get("https://hogehoge.com/foo.jpg")

requests.get()の戻り値(詳細後述)から、送信したheaderが分かります。上のget()では、下のようなヘッダーになります。

"User-Agent": "python-requests/2.25.1",
"Accept": "*/*",        # MIMEタイプ
"Accept-Encoding": "gzip, deflate",     # 通信の圧縮形式

誤ったUser-Agentでリクエストを送った結果と確認方法

参考までに、”User-Agent”の未設定に気づいた過程を書いておきます。

これが誤った設定で数十回もリクストしたコードです。

import requests


res = requests.get("https://hogehoge.com/foo.jpg")
with open("get.jpg", "wb") as f:
    f.write(res.content)

リクエストの送信結果

res.status_code = 200
res.content = b'~'
res.url = 'https://hogehoge.com/wahaha.jpg'
res.request.headers 

res.status_codeは、200で成功です。しかし、PC上のget.jpgは、サーバ上のfoo.jpgとは異なります。jpgのファイルサイズも違います。途中で切れているのではなく、別のjpgファイルです。

また、requestsの戻り値を見ると、https://hogehoge.com/foo.jpgをダウンロードしたいのに、https://hogehoge.com/wahaha.jpgが返されています。

“User-Agent”は、res.request.headersで確認します。

res.request.headersの内訳

'User-Agent': 'python-requests/2.25.1',
'Accept-Encoding': 'gzip, deflate',
'Accept': '*/*',
'Connection': 'keep-alive'

‘User-Agent’ に 機械的なアクセスと疑われる “python-requests/2.25.1” が設定されています。

そこで、先のサンプルで取得するように切り替えたところ、ダウンロードできるようになりました。

User-Agentを偽装せずに安全に画像を取得する方法

ダウンロード対象がブラウザで表示できるイメージファイルの場合、他の方法もあります。

【Python】Seleniumで安全に画像保存する方法
Seleniumを使ったPythonによるスクレイピングで、イメージファイルをダウンロードをする方法です。ダウンロードのため、もう一回サーバにgetリクエストするのは無駄な気がしたので、ブラウザに表示されているものを保存します。 ...

こちらの方がサーバ側で対策される危険性がなく、メリットは絶大です。

コメント

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