requests for python で、巨大なfileをhttp getする場合、stream=True で chunk化 - end0tknr's kipple - web写経開発
以前の上記entryの修正版です。
国土交通省で公開している不動産取引価格情報取得API ( https://www.land.mlit.go.jp/webland/api.html )に対し、 python3標準の urllib.request を用い
import urllib.request http_conf = {"retry_limit":3, "retry_sleep":5 } def get_http_requests(self, req_or_url,req_timeout=5): i = 0 while i < http_conf["retry_limit"]: i += 1 try: http_res = urllib.request.urlopen(req_or_url, timeout=req_timeout) html_content = http_res.read() return html_content except Exception as e: if "404: Not Found" in str(e): logger.error("{} {}".format(req_or_url, e)) return None logger.warning(e) logger.warning("retry {} {}".format(i,req_or_url)) time.sleep(http_conf["retry_sleep"]) return None
のように http getを行うと、本来、数MBの要領がある影響でしょうか、 レスポンスが途中で途切れてしまいます。
https://docs.python.org/ja/3/library/urllib.request.html を見ると、 「 より高水準のHTTPクライアントインターフェースとして Requestsパッケージ がお奨めです。」 という記載がありましたので、
「pip install requests」した上で、以下のように requests を用い、かつ、「stream=True」で分割ダウンロードすることで解消
import requests def get_http_requests(self,req_url): i = 0 while i < 3: # 最大3回 retry i += 1 try: # 先方サーバによっては http response codeを返さない為、try-except res = requests.get(req_url, timeout=(5,60), stream=True) except Exception as e: logger.warning(e) logger.warning("retry {} {}".format(i,req_url)) time.sleep(10) if res.status_code == 404: logger.error( "404 error {}".format(req_url) ) return try: res.raise_for_status() except Exception as e: logger.warning(e) logger.warning("retry {} {}".format(i,req_url)) time.sleep(10) # 大容量の為か urllib.request.urlopen()では # response contentを取得できなかった為、stream=True で chunk化 chunks = [] for chunk in res.iter_content(chunk_size=1024*1024): chunks.append(chunk) content = b"".join(chunks).decode() return json.loads( content )