0

私は Yahoo Api を使用しています。ハード スリープを追加したことに加えて、ランダム スリープ メソッドを実装しましたが、最初の試行で応答が得られない場合、待機または再試行する方法がわかりません。

たとえば、以下に示したコードは、一部のユーザーで完全にランダムに失敗します。失敗した後、ブラウザでURLを取得すると、魅力的に機能します。だから私の質問はなぜですか?どうすればこれを解決できますか? または、ハードスリープ後に別のリクエストを行うようにこのコードを改善できますか (それが良いアプローチである場合のみ)

追加するのを忘れた情報がいくつかあります。コードを変更して、http 成功コードを取得しました。

print urlobject.getcode()

200 を返しますが、json は返されません。

注: URL から appid(Key) を削除しました

# return the json question for given question id
def returnJSONQuestion(questionId):
    randomSleep()
    url = 'http://answers.yahooapis.com/AnswersService/V1/getQuestion?appid=APPIDREMOVED8&question_id={0}&output=json'
    format_url = url.format(questionId)
    try:
        request = urllib2.Request(format_url)
        urlobject = urllib2.urlopen(request)
        time.sleep(10)
        jsondata = json.loads(urlobject.read().decode("utf-8"))
        print jsondata
    except urllib2.HTTPError, e:
        print e.code
        logging.exception("Exception")
    except urllib2.URLError, e:
        print e.reason
        logging.exception("Exception")
    except(json.decoder.JSONDecodeError,ValueError):
        print 'Question ID ' + questionId + ' Decode JSON has failed'
        logging.info("This qid didn't work " + questionId)
    return jsondata
4

3 に答える 3

5

さて、最初に、あなたの質問に直接答えないが、役立つかもしれないいくつかのポイント:

1)urllib2.urlopenを呼び出してから、返されたaddinfourlオブジェクトを読み取るまで待つ必要はないと確信しています。http://docs.python.org/library/urllib2.html#examplesの例には、そのようなスリープは含まれていません。

2)

json.loads(urlobject.read().decode("utf-8"))

単純化して

json.load(urlobject)

これはよりシンプルで読みやすいです。基本的に、.loadは引数としてファイルのようなオブジェクトを取りますが、.loadsは文字列を取ります。utf-8からデータをデコードするには、最初にデータをread()する必要があると思われたかもしれませんが、.loadはデフォルトで、読み取っているオブジェクトがasciiまたはutf-であると想定しているため、これは実際には問題ありません。 8エンコードされています(http://docs.python.org/library/json.html#json.loadを参照)。

3)現在の目的には関係ないかもしれませんが、ここでの例外処理は悪いと思います。「try:」ブロック中に問題が発生した場合、変数jsondataは割り当てられていません。次に、try / exceptionブロックの終了後にそれを返そうとすると、割り当てられていない変数を使用しようとしたためにNameErrorが発生します。つまり、アプリケーション内の他の関数がreturnJSONQuestionを呼び出して例外が発生した場合、外部関数が認識するのは元の例外ではなくNameErrorであり、外部関数が生成するトレースバックはその場所を指しません。本当の問題が発生しました。これは、何がうまくいかなかったかを理解しようとするときに、簡単に混乱を引き起こす可能性があります。したがって、ここでの「を除く」すべてのブロックが「レイズ」で終了した方がよいでしょう。

4)Pythonでは、関数がdocstringとして何をするか( http://www.python.org/dev/peps/pep-0257/#what-is-a-docstringを参照)というコメントを付けることをお勧めします。関数の上のコメントとして。

とにかく、実際にあなたの質問に答えるために...

さまざまな理由でURLを開こうとすると、一見ランダムなURLErrorが発生する可能性があります。リクエストの処理中にサーバーにバグがあった可能性があります。接続に問題があり、一部のデータがドロップされた可能性があります。管理者の1人が設定を変更したり、更新をプッシュしたりしているときに、サーバーが数秒間ダウンした可能性があります。多分完全に何か他のもの。少しWeb開発を行った後、一部のサーバーは他のサーバーよりもはるかに信頼性が高いことに気付きましたが、ほとんどの実際の目的では、おそらく理由を心配する必要はないと思います。最も簡単な方法は、成功するまでリクエストを再試行することです。

上記のすべてを念頭に置いて、以下のコードはおそらく必要なことを実行します。

def returnJSONQuestion(questionId):
    """return the json question for given question id"""

    url = 'http://answers.yahooapis.com/AnswersService/V1/getQuestion?appid=APPIDREMOVED8&question_id={0}&output=json'
    format_url = url.format(questionId)
    try:
        request = urllib2.Request(format_url)

        # Try to get the data and json.load it 5 times, then give up
        tries = 5
        while tries >= 0:
            try:
                urlobject = urllib2.urlopen(request)
                jsondata = json.load(urlobject)
                print jsondata
                return jsondata
            except:
                if tries == 0:
                    # If we keep failing, raise the exception for the outer exception
                    # handling to deal with
                    raise
                else:
                    # Wait a few seconds before retrying and hope the problem goes away
                    time.sleep(3) 
                    tries -= 1
                    continue

    except urllib2.HTTPError, e:
        print e.code
        logging.exception("Exception")
        raise
    except urllib2.URLError, e:
        print e.reason
        logging.exception("Exception")
        raise
    except(json.decoder.JSONDecodeError,ValueError):
        print 'Question ID ' + questionId + ' Decode JSON has failed'
        logging.info("This qid didn't work " + questionId)
        raise

お役に立てれば!プログラムでさまざまなWebリクエストを作成する場合は、この「例外の再試行リクエスト」ロジックをどこかの関数に抽象化して、定型的な再試行を行う必要がないようにすることをお勧めします。ロジックが他のものと混ざり合っています。:)

于 2012-10-19T19:33:10.900 に答える
2

私はこのような問題にたくさん遭遇しました。私は通常、API リクエスト ラッパーまたはブラウザの「get」を次のように実装します。

def get_remote( url , attempt=0 ):
   try :
       request = urllib2.Request(format_url)
       urlobject = urllib2.urlopen(request)
       ...
       return data
   except urllib2.HTTPError , error:
       if error.code in ( 403 , 404 ):
           if attempt < MAX_ATTEMPTS :
                return get_remote( url , attempt=attempt+1 )
       raise

URL または試行に基づいて、リクエスト パラメータも変更します。たとえば、特定の Web サイトは Python で識別されたブラウザーをブロックします。そのため、正規表現に一致する場合は、ユーザー エージェントを Firefox に交換します。あるいは、最初の試行で何かが失敗した場合は、常に 2 回目のリクエストで Firefox/Safari を試すか、後続の試行の間にランダムなタイムアウトを実装します。

于 2012-10-19T19:41:41.167 に答える
1

失敗の理由はわかりません。これはYahooのスロットリング制限である可能性があります(またはそうでない可能性があります)が、実際には、質問IDを保存することをお勧めします。これにより、失敗が発生し、後で再試行します。

これは簡単に行うことができます。関数を少し変更します。

def returnJSONQuestion(questionId):
    randomSleep()
    jsondata = None
    url = 'http://answers.yahooapis.com/AnswersService/V1/getQuestion?appid=APPIDREMOVED8&question_id={0}&output=json'
    format_url = url.format(questionId)
    try:
        request = urllib2.Request(format_url)
        urlobject = urllib2.urlopen(request)
        time.sleep(10)
        jsondata = json.loads(urlobject.read().decode("utf-8"))
        print jsondata
    except urllib2.HTTPError, e:
        print e.code
        logging.exception("Exception")
    except urllib2.URLError, e:
        print e.reason
        logging.exception("Exception")
    except(json.decoder.JSONDecodeError,ValueError):
        print 'Question ID ' + questionId + ' Decode JSON has failed'
        logging.info("This qid didn't work " + questionId)
    return jsondata

そして、どんな失敗の場合でも、この関数はあなたにNoneを返します。したがって、結果を確認し、それがNoneの場合は、質問IDをリストに保存してから、約3回再試行できます。二度目はもっとラッキーかもしれません。

もちろん、関数を変更することもできるので、エラーが発生すると同時にリクエストを数回再試行しますが、最初の解決策の方が私には適しています。

ところで、「User-Agent」ヘッダーを実際のブラウザ値に設定します。通常、このような場合にも良い考えです。たとえば、Googleは、このような「ロボパーサー」の結果を返さない場合が多くあります。

于 2012-10-19T19:28:53.700 に答える