HTTPエラー429(リクエストが多すぎる)Pythonを回避する方法


91

Pythonを使用してWebサイトにログインし、いくつかのWebページから情報を収集しようとすると、次のエラーが発生します。

Traceback (most recent call last):
  File "extract_test.py", line 43, in <module>
    response=br.open(v)
  File "/usr/local/lib/python2.7/dist-packages/mechanize/_mechanize.py", line 203, in open
    return self._mech_open(url, data, timeout=timeout)
  File "/usr/local/lib/python2.7/dist-packages/mechanize/_mechanize.py", line 255, in _mech_open
    raise response
mechanize._response.httperror_seek_wrapper: HTTP Error 429: Unknown Response Code

私は使用time.sleep()しましたが機能しますが、インテリジェントで信頼性が低いようですが、このエラーを回避する他の方法はありますか?

これが私のコードです:

import mechanize
import cookielib
import re
first=("example.com/page1")
second=("example.com/page2")
third=("example.com/page3")
fourth=("example.com/page4")
## I have seven URL's I want to open

urls_list=[first,second,third,fourth]

br = mechanize.Browser()
# Cookie Jar
cj = cookielib.LWPCookieJar()
br.set_cookiejar(cj)

# Browser options 
br.set_handle_equiv(True)
br.set_handle_redirect(True)
br.set_handle_referer(True)
br.set_handle_robots(False)

# Log in credentials
br.open("example.com")
br.select_form(nr=0)
br["username"] = "username"
br["password"] = "password"
br.submit()

for url in urls_list:
        br.open(url)
        print re.findall("Some String")

6
それを回避する方法はありません。これは、サーバー側での強制であり、リクエスト/ time-unitの数を追跡します。このユニットを超えると、一時的にブロックされます。一部のサーバーはこの情報をヘッダーで送信しますが、それらの状況はまれです。サーバーから受け取ったヘッダーを確認し、入手可能な情報を使用します。そうでない場合は、引っ掛かることなくハンマーで打つ速度を確認し、を使用しsleepます。
2014

回答:


158

ステータス429の受信はエラーではありません。これは、リクエストのスパム送信を停止するように「親切に」要求している他のサーバーです。明らかに、リクエストの割合が高すぎるため、サーバーはこれを受け入れません。

これを「回避」したり、IPのなりすましを試みてサーバーのセキュリティ設定を回避しようとしたりする必要はありません。あまり多くのリクエストを送信しないことでサーバーの回答を尊重する必要があります。

すべてが適切に設定されている場合は、429応答とともに「Retry-after」ヘッダーも受け取ります。このヘッダーは、別の呼び出しを行う前に待機する秒数を指定します。この「問題」に対処する適切な方法は、このヘッダーを読み取り、その秒数だけプロセスをスリープさせることです。

ステータス429の詳細については、http//tools.ietf.org/html/rfc6585#page-3を参照してください。


23
まあ、誰もすべてのWebサーバーが正しく構成されているとは言いませんでした。また、ほとんどのレートリミッターは訪問者をIPで識別しているため、IPが動的に共有されるシナリオでは問題が発生する可能性があります。あまり多くのリクエストを送信していないと確信しているにもかかわらず、ステータス429を受信し続ける場合は、サイトの管理者に連絡することを検討してください。
MRA

2
"Retry-after"ヘッダーについて言及していただきありがとうございます。その値を取得する方法を確認するコード例が大好きです(私はurllibを使用して、OPを機械化しました。どちらの場合も、ヘッダーは発生した例外に含まれていないと思います)
MacFreek

@MacFreek特定のPythonコードの例はまだ用意していませんが、一般に応答ヘッダーを取得する方法に関するいくつかの例は、この質問への回答から取得できると想定しています:stackoverflow.com/q/843392
MRA

@MRAに感謝します。ヘッダーも例外で使用できることがわかりました:をキャッチした後、少なくともurllib2ではでHTTPError as my_exception使用できますmy_exception.headers
MacFreek 2018

37

このコードを書いて私の問題を修正しました:

requests.get(link, headers = {'User-agent': 'your bot 0.1'})


26
この回答は反対ですが、他の人からの虐待のためにユーザーエージェントが禁止された場合、一部のサイトは自動的にエラーコード429を返します。少数のリクエストしか送信していなくてもエラーコード429が表示される場合は、ユーザーエージェントを別の値に設定してみてください。
Ferry Boender 2017年

7
追加したいと思います。ユーザーエージェントが送信されない限り、一部のサイトは要求を明白に拒否し、無数の他の応答を受け取る可能性があります:503/403 /いくつかの一般的なインデックスページ。
user3791372 2017年

1
これを確認できます。ただ、のredditでのpythonをインタフェースしようとするとユーザーエージェントを設定せずに、私はいつも、エラーコード429になっていた
Karrq

説明を追加していただけますか?
Tokci

29

MRAが言ったように、回避するのではなく、429 Too Many Requestsそれに応じて処理する必要があります。ユースケースに応じて、いくつかのオプションがあります。

1)プロセスをスリープ状態にします。サーバーは通常、Retry-after再試行する前に待機する必要がある秒数を含むヘッダーを応答に含めます。プロセスをスリープ状態にすると、タスクキューなどで問題が発生する可能性があることに注意してください。代わりに、後でタスクを再試行して、ワーカーを他のものに解放する必要があります。

2)指数バックオフ。サーバーが待機時間を教えてくれない場合は、一時停止を増やしてリクエストを再試行できます。人気のタスクキューCeleryには、この機能が組み込まれています。

3)トークンバケット。この手法は、特定の時間内に実行できる要求の数が事前にわかっている場合に役立ちます。APIにアクセスするたびに、最初にバケットからトークンをフェッチします。バケットは一定の割合で補充されます。バケットが空の場合は、APIに再度アクセスする前に待機する必要があることがわかります。トークンバケットは通常、もう一方の端(API)に実装されますが、これらをプロキシとして使用して、を取得しないようにすることもできます429 Too Many RequestsCeleryrate_limit機能は、トークンバケットアルゴリズムを使用します。

以下は、指数バックオフとレート制限/トークンバケットを使用したPython / Celeryアプリの例です。

class TooManyRequests(Exception):
"""Too many requests"""

@task(
   rate_limit='10/s',
   autoretry_for=(ConnectTimeout, TooManyRequests,),
   retry_backoff=True)
def api(*args, **kwargs):
  r = requests.get('placeholder-external-api')

  if r.status_code == 429:
    raise TooManyRequests()

9

別の回避策は、ある種のパブリックVPNまたはTorネットワークを使用してIPを偽装することです。これは、IPレベルでのサーバーのレート制限を想定しています。

urllib2とともにtorを使用する方法を示す簡単なブログ投稿があります。

http://blog.flip-edesign.com/?p=119


8
これが、APIのユーザーにリクエストを行うためのキーを登録することを常に要求する理由です。これにより、IPではなくキーでリクエストを制限できます。別のキーを登録することが、より高い制限を取得する唯一の方法です。
Mnebuerquo

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.