Pythonのurlopenを複数回リトライする方法

Pythonを使っていると、urllibのurlopen関数を使ってHTTPリソースなどを取得するというのはよくあると思います。ただ、瞬間的にサーバーダウンがビジーになっていて、HTTPコンテンツが返ってこないこともままあると思います。これを回避するための、通信に失敗したらある一定回数リクエストを投げる処理をwithステートメントを使って実現するコードを書きました。(よくある処理なので、もしかしたら標準で組み込まれているかもしれませんが。。。)

with文を使って一定の回数通信をリトライするサンプル

with文を使ってある一定の回数通信をリトライするためには、まずは以下のようなコードを用意します。

# coding: utf-8

import time
import urllib
from contextlib import contextmanager
@contextmanager
def fetch_url(url, max_times=10, sleep_sec=5):
    """
    HTTP通信をしてステータスコード200が返ってこなかった場合、
    一定の回数再試行をします。 一定の回数試しても駄目な場合、
    最後に開いたファイルオブジェクトを返します。
    Args:
        max_times: 最大試行回数
        sleep_sec: 接続失敗時にスリープする秒数
    例:
        with fetch_url('http://www.18th-technote.com/') as f:
            f.read()
    """
    retry_count = 0
    while True:
        f = urllib.urlopen(url)
        try:
            retry_count += 1
            if f.getcode() == 200 or retry_count >= max_times:
                # 200が返ってくるか、最大試行回数に到達した場合
                # ファイルオブジェクトをyieldした後にループを抜けます。
                yield f
                break
            time.sleep(sleep_sec)
        finally:
            f.close()

これを用意しておけば、後はwith文で指定するだけである一定回数通信をリトライすることができます。

# coding: utf-8

def main():
    with fetch_url('http://www.18th-technote.com/dummy', sleep_sec=1) as f:
        print f.read()

上記コードを実行すると、「http://www.18th-technote.com/dummy」にアクセスをします。そのレスポンスのコードが200なら取得したリソースを返します。もし200出ない場合は1秒間スリープし、再度同じリソースにアクセスします。それでも駄目な場合はさらに繰り返し、合計10回通信を試みます。

このように、この関数をwithとともに使えば、瞬間的に接続先がダウンしていた場合の処理が書きやすくなります。

この記事が役に立った場合、シェアしていただけると励みになります!!