HTTPを扱っていると、リクエストの失敗は避けられない現実であり、それに対処する必要があります。ウェブ開発では、200 というステータスは良いレスポンスを示します。しかし、常に 200 が返ってくるとは限りません。このガイドでは、200 以外のステータスコードの扱い方について説明します。
Mozillaによると、ステータスコードは以下のカテゴリーに分けられる:
- 100-199:情報提供
- 200-299:成功した回答
- 300-399:リダイレクション・メッセージ
- 400-499:クライアントエラーメッセージ
- 500-599:サーバーエラーメッセージ
ステータス・コードとは?
エラーコードは重要である。ウェブスクレイパーのようなクライアント側のプログラムを構築する場合、主に400以上と500以上のステータスコードに注目する必要がある。400番台のコードは一般的に、認証の問題、レート制限、タイムアウト、悪名高い404のようなクライアント側のエラーをカバーします:File Not Foundエラーなどです。500番台のコードでは、一般的にサーバーの問題を調べます。
何十年もの間、Mozilla はW3CとIETF のウェブ開発標準を文書化してきました。以下は、あなたが遭遇するかもしれない一般的なエラーコードのリストです。このリストは網羅的ではありません。これらのエラーは、Mozilla の公式文書に記載されているものです。あなたのターゲットサイトによっては、コードが多少異なるかもしれませんが、ロジックは同じままであるべきです。
ステータスコード | 意味 | 説明 |
---|---|---|
400 | 悪いリクエスト | リクエストフォーマットの確認 |
401 | 無許可 | APIキーの確認 |
403 | 禁止 | このデータにはアクセスできません。 |
404 | 見つかりません | サイト/エンドポイントが存在しない |
408 | リクエストタイムアウト | リクエストがタイムアウトしました。 |
429 | リクエストが多すぎる | リクエストを遅くする |
500 | 内部サーバーエラー | 一般的なサーバーエラー、リクエストの再試行 |
501 | 未実施 | サーバーはまだこれをサポートしていない |
502 | バッド・ゲートウェイ | 上流サーバーからの応答失敗 |
503 | サービス利用不可 | サーバーが一時的にダウンしています。 |
504 | ゲートウェイタイムアウト | 上流サーバー待ちでタイムアウト |
リトライ戦略
リトライの仕組みを実装する場合、HTTPAdapter や Tenacity のような組み込み済みのライブラリを使うことができます。場合によっては、独自の再試行ロジックを書きたくなるかもしれません。
一般的には、リトライの上限と、リトライを中止するための戦略が必要だ。リトライの無限ループに巻き込まれないようにするために、リミットが必要なのだ。ホストサーバーを尊重するために、少しずつ手を引いていく必要がある。リクエストが早すぎると、ブロックされたり、サーバーに負担がかかったりします。
- リトライ制限:制限を設定する必要がある。X回リトライすると、スクレーパーは諦める。
- バックオフ・アルゴリズム:これは比較的シンプルだ。小さなバックオフから始めて、リトライのたびに増やしていく。0.3から始め、0.6、1.2と増やしていく。
ある限度までリクエストを再試行したい。各リクエストが失敗したら、もう少し待ちたい。
HTTPアダプタ
allowed_methods
は必須ではありませんが、再試行条件を定義することでコードをより安全にします。以下のコードでは、httpbinを使用して自動的にエラーを発生させ、再試行ロジックをトリガーしています。
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
#create a session
session = requests.Session()
#configure retry settings
retry = Retry(
total=3, #maximum retries
backoff_factor=0.3, #time between retries (exponential backoff)
status_forcelist=(429, 500, 502, 503, 504), #status codes to trigger a retry
allowed_methods={"GET", "POST"}
)
#mount the adapter with our custom settings
adapter = HTTPAdapter(max_retries=retry)
session.mount("http://", adapter)
session.mount("https://", adapter)
#actually make a request with our retry logic
try:
print("Making a request with retry logic...")
response = session.get("https://httpbin.org/status/500")
response.raise_for_status()
print("✅ Request successful:", response.status_code)
except requests.exceptions.RequestException as e:
print("❌ Request failed after retries:", e)
Session
オブジェクトを作成したら、次のようにします:
Retry
オブジェクトを作成し、以下のように定義する:total
: リクエストを再試行する上限。backoff_factor
:再試行までの待ち時間。リトライ回数が増えるにつれて指数関数的に調整される。status_forcelist
:バッドステータスコードのリスト。このリストにあるコードは自動的にリトライのトリガーとなる。
HTTPAdapter
オブジェクトを作成し、retry
変数を指定します:adapter = HTTPAdapter(max_retries=retry)
.アダプタを
作成したら、session.mount() を
使用して HTTP および HTTPS メソッドにマウントします。
このコードを実行すると、3回のリトライ(合計=3
)が実行され、次のような出力が得られます。
Making a request with retry logic...
❌ Request failed after retries: HTTPSConnectionPool(host='httpbin.org', port=443): Max retries exceeded with url: /status/500 (Caused by ResponseError('too many 500 error responses'))
粘り強さ
Python用のオープンソースのリトライライライブラリとして有名なTenacityを使うこともできる。HTTPに限ったことではありませんが、リトライを実装するための表現力豊かで理解しやすい方法を提供してくれます。
まず、インストールする必要がある。
pip install tenacity
インストールしたら、デコレーターを作成してリクエスト関数をラップします。retry
デコレータで、stop
引数、wait
引数、retry
引数を追加します。
import requests
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type, RetryError
#define a retry strategy
@retry(
stop=stop_after_attempt(3), #retry up to 3 times
wait=wait_exponential(multiplier=0.3), #exponential backoff
retry=retry_if_exception_type(requests.exceptions.RequestException), #retry on request failures
)
def make_request():
print("Making a request with retry logic...")
response = requests.get("https://httpbin.org/status/500")
response.raise_for_status()
print("✅ Request successful:", response.status_code)
return response
# Attempt to make the request
try:
make_request()
except RetryError as e:
print("❌ Request failed after all retries:", e)
ここでのロジックと設定は、HTTPAdapterを使った最初の例とよく似ている。
stop=stop_after_attempt(3):
これはtenacity
に、3 回再試行に失敗したら諦めるように指示する。wait=wait_exponential(multiplier=0.3)
は、前に使ったのと同じwaitを使う。また、前と同じように指数関数的に後退します。retry=retry_if_exception_type(requests.exceptions.RequestException)は
、RequestExceptionが
発生するたびにこのロジックを使うようにtenacityに
指示します。make_request() は
、エラーエンドポイントへのリクエストを行います。このメソッドは、上で作成したデコレータからすべての trait を受け取ります。
このコードを実行すると、同じような出力が得られる。
Making a request with retry logic...
Making a request with retry logic...
Making a request with retry logic...
❌ Request failed after all retries: RetryError[<Future at 0x75e762970760 state=finished raised HTTPError>]
独自のリトライ・メカニズムを構築する
独自のリトライ・メカニズムを構築することもできる。カスタムコードを扱う場合、これが最良のアプローチになることが多い。比較的少ないコード量で、これらのライブラリから得られるのと同じ効果を得ることができる。
以下のコードでは、指数バックオフのためにsleepを
インポートする必要がある。total
、backoff_factor
、bad_codesを
設定する。リトライのロジックを保持するためにwhile
ループを使用します。
import requests
from time import sleep
#create a session
session = requests.Session()
#define our retry settings
total = 3
backoff_factor = 0.3
bad_codes = [429, 500, 502, 503, 504]
#try counter and success boolean
current_tries = 0
success = False
#attempt until we succeed or run out of tries
while current_tries < total and not success:
try:
print("Making a request with retry logic...")
response = session.get("https://httpbin.org/status/500")
if response.status_code in bad_codes:
raise requests.exceptions.HTTPError(f"Received {response.status_code}, triggering retry")
print("✅ Request successful:", response.status_code)
success = True
except requests.exceptions.RequestException as e:
print(f"❌ Request failed: {e}, retries left: {total-current_tries}")
sleep(backoff_factor)
backoff_factor = backoff_factor * 2
current_tries+=1
ここでの実際のロジックは、単純なwhile
ループで処理される。
response.status_codeが
bad_codesの
リストに含まれている場合、例外をスローします。- リクエストに失敗した場合、私たちは
- エラーメッセージをコンソールに表示する。
sleep(backoff_factor) は
、次のリクエストを送る前に待つ。backoff_factor = backoff_factor * 2は
、次のトライのためのbackoff_factorを
2倍にする。current_triesを
インクリメントすることで、ループに無限に留まらないようにしている。
これがカスタム再試行ロジックの出力です。
Making a request with retry logic...
❌ Request failed: Received 500, triggering retry, retries left: 3
Making a request with retry logic...
❌ Request failed: Received 500, triggering retry, retries left: 2
Making a request with retry logic...
❌ Request failed: Received 500, triggering retry, retries left: 1
ブロックを乗り越える
野生のサイトでは、あなたをブロックするサイトもあるでしょう。Pythonのリクエストには常にプロキシを使うのがベストプラクティスです。プロキシを使うと、リクエストは別のマシンを経由するようになります。これはあなたのアイデンティティを保護し、あなたの IP アドレスがターゲットサイトにブロックされるのを防ぎます。IPブロックを突破するための詳しいガイドもあります。私たちの住宅用プロキシは、これらの課題を克服するために構築されています。
結論
これでPythonでHTTPリクエストに失敗したときの対処法がわかったと思います。スクレイパーやAPIクライアント、自動化ツールを書いているのであれば、これらの問題をどのように扱うべきかを知っているはずです。あらゆる種類の失敗したリクエストを避けるために、私たちはWeb Unlocker APIやScraping Browser のような製品を開発しました。これらのツールは、ボット対策、CAPTCHAチャレンジ、IPブロックを自動的に処理し、最も困難なウェブサイトでもシームレスで効率的なウェブスクレイピングを保証します。
今すぐ登録し、無料トライアルを開始しましょう。