HTTP hatası 429 (Çok Fazla İstek) python nasıl önlenir


94

Bir web sitesinde oturum açmak ve birkaç web sayfasından bilgi toplamak için Python'u kullanmaya çalışıyorum ve aşağıdaki hatayı alıyorum:

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

Kullandım time.sleep()ve işe yarıyor, ancak akıllıca ve güvenilmez görünüyor, bu hatayı atlatmanın başka bir yolu var mı?

İşte kodum:

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
Bunun etrafında bir yol yok, bu, sunucu tarafında kaç istek / zaman birimi yaptığınızı takip eden bir yaptırımdır. Bu birimi aşarsanız, geçici olarak engellenirsiniz. Bazı sunucular bu bilgiyi başlıkta gönderir, ancak bu durumlar nadirdir. Sunucudan alınan başlıkları kontrol edin, mevcut bilgileri kullanın .. Değilse, yakalanmadan ne kadar hızlı çekiçleyebileceğinizi kontrol edin ve a sleep.
2014

Yanıtlar:


158

429 durumunun alınması bir hata değildir , diğer sunucu "nazikçe" sizden istenmeyen posta isteklerini durdurmanızı rica eder. Açıkçası, istek oranınız çok yüksek ve sunucu bunu kabul etmeye istekli değil.

Bunu "atlatmaya" çalışmamalı, hatta IP'nizi aldatmaya çalışarak sunucu güvenlik ayarlarını atlatmaya çalışmamalısınız, çok fazla istek göndermeyerek sunucunun cevabına saygı göstermelisiniz.

Her şey doğru bir şekilde ayarlanmışsa, 429 yanıtıyla birlikte bir "Yeniden dene" başlığı da alacaksınız. Bu başlık, başka bir arama yapmadan önce beklemeniz gereken saniye sayısını belirtir. Bu "problem" ile başa çıkmanın doğru yolu, bu başlığı okumak ve işleminizi o kadar saniye boyunca uyumaktır.

429 durumu hakkında daha fazla bilgiyi burada bulabilirsiniz: http://tools.ietf.org/html/rfc6585#page-3


23
Hiç kimse tüm web sunucularının doğru yapılandırıldığını söylemedi. Ayrıca, oran sınırlayıcıların çoğu ziyaretçileri IP'ye göre belirlediğinden, bu IP'lerin dinamik olarak paylaşıldığı bir senaryoda sorunlara yol açabilir. Çok fazla istek göndermediğinizden emin olmanıza rağmen 429 durumunu almaya devam ederseniz, site yöneticisine başvurmayı düşünebilirsiniz.
MRA

2
"Sonra tekrar dene" başlığından bahsettiğiniz için teşekkür ederiz. Bu değeri nasıl elde edeceğimi görmek için bir kod örneğini çok isterim (OP mekanize etmek için urllib kullanıyordum, her iki durumda da başlıkların yükseltilmiş istisnaya dahil olduğunu düşünmüyorum)
MacFreek

@MacFreek Hazır herhangi bir Python kod örneğim yok, ancak genel olarak yanıt başlıklarının nasıl alınacağına dair bazı örnekler bu sorunun yanıtlarından alınabilir: stackoverflow.com/q/843392
MRA

Teşekkürler @MRA. Başlıkların istisnada da mevcut olduğunu buldum: yakaladıktan sonra , en azından urllib2 için HTTPError as my_exceptionmevcut my_exception.headers.
MacFreek

38

Bu kod parçasını yazmak sorunumu çözdü:

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


26
Bu yanıt reddedilir, ancak bazı siteler, kullanıcı aracısı başkalarının kötüye kullanımı nedeniyle yasaklanırsa otomatik olarak 429 hata kodunu döndürür. Yalnızca birkaç istek göndermiş olsanız bile 429 hata kodunu alırsanız, kullanıcı aracısını başka bir şeye ayarlamayı deneyin.
Ferry Boender 01

7
Ayrıca eklemek isterim ki, bazı siteler, bir kullanıcı aracısı gönderilmedikçe istekleri açıkça reddeder ve sayısız başka yanıt alabilirsiniz: 503/403 / bazı genel dizin sayfası.
user3791372

1
Bunu teyit edebilir.
Python'u

1
biraz açıklama ekler misin lütfen?
Tokci

"Bu kod parçasını" nereye yazarsınız? Bu çözümün daha fazla ayrıntıya ihtiyacı var.
Joe McLean

29

MRA'nın dediği gibi, a'dan kaçmaya çalışmamalısınız, 429 Too Many Requestsbunun yerine ona göre davranmalısınız . Kullanım durumunuza bağlı olarak birkaç seçeneğiniz vardır:

1) Sürecinizi uyuyun . Sunucu genellikle Retry-afteryanıtta, yeniden denemeden önce beklemeniz gereken saniye sayısını içeren bir başlık içerir . Bir süreci uyumanızın sorunlara neden olabileceğini unutmayın, örneğin bir görev kuyruğunda, bunun yerine çalışanı başka şeyler için serbest bırakmak için daha sonra görevi yeniden denemeniz gerekir.

2) Üstel geri çekilme . Sunucu size ne kadar bekleyeceğinizi söylemezse, aradaki duraklamaları artırarak isteğinizi yeniden deneyebilirsiniz. Popüler görev kuyruğu Kereviz, bu özelliğe doğrudan sahiptir .

3) Jeton kovası . Bu teknik, belirli bir süre içinde kaç talepte bulunabileceğinizi önceden biliyorsanız kullanışlıdır. API'ye her eriştiğinizde, önce paketten bir jeton alırsınız. Kova sabit bir hızda yeniden doldurulur. Paket boşsa, API'ye tekrar basmadan önce beklemeniz gerektiğini bilirsiniz. Jeton paketleri genellikle diğer uçta (API) uygulanır, ancak bunları bir 429 Too Many Requests. Kereviz rate_limit özelliği belirteç kova algoritma kullanır.

Üstel geri çekilme ve hız sınırlama / belirteç grubu kullanan bir Python / Celery uygulamasına bir örnek:

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

Başka bir geçici çözüm, IP'nizi bir tür Genel VPN veya Tor ağı kullanarak aldatmak olabilir. Bu, sunucudaki IP düzeyinde hız sınırlamasını varsayar.

Urllib2 ile birlikte tor kullanmanın bir yolunu gösteren kısa bir blog yazısı var:

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


8
Bu nedenle, API'lerimin kullanıcılarından her zaman istekte bulunmaları için bir anahtara kaydolmalarını istiyorum. Bu şekilde istekleri IP yerine anahtara göre sınırlayabilirim. Daha yüksek bir limit elde etmenin tek yolu başka bir anahtar için kaydolmaktır.
Mnebuerquo

4
if response.status_code == 429:
  time.sleep(int(response.headers["Retry-After"]))

1

Siteleri toplarken IP engellemeye yönelik güzel bir çözüm buldum . Bir Kazıyıcıyı Google App Engine'den çalıştırarak ve 429 aldığınızda otomatik olarak yeniden dağıtarak süresiz olarak çalıştırmanıza olanak tanır.

Bu makaleye göz atın


Haha vay canına ... Google'ı Google'ı kazımak için kullanıyor. Ve sonra Google engellediğinde Google IP'nizi değiştirin.
sam1370
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.