วิธีหลีกเลี่ยงข้อผิดพลาด HTTP 429 (คำขอมากเกินไป) python


94

ฉันพยายามใช้ Python เพื่อเข้าสู่เว็บไซต์และรวบรวมข้อมูลจากหลาย ๆ หน้าเว็บและฉันได้รับข้อผิดพลาดต่อไปนี้:

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
ไม่มีทางหลีกเลี่ยงได้นี่คือการบังคับใช้ในฝั่งเซิร์ฟเวอร์เพื่อติดตามจำนวนคำขอ / หน่วยเวลาที่คุณทำ หากคุณเกินหน่วยนี้คุณจะถูกบล็อกชั่วคราว เซิร์ฟเวอร์บางตัวส่งข้อมูลนี้ในส่วนหัว แต่โอกาสเหล่านั้นหายาก ตรวจสอบส่วนหัวที่ได้รับจากเซิร์ฟเวอร์ใช้ข้อมูลที่มี .. ถ้าไม่ตรวจสอบว่าคุณสามารถตอกได้เร็วแค่ไหนโดยไม่ถูกจับและใช้ a sleep.
Torxed

คำตอบ:


158

การรับสถานะ 429 ไม่ใช่ข้อผิดพลาดเซิร์ฟเวอร์อื่น "กรุณา" ขอให้คุณหยุดการร้องขอการส่งสแปม เห็นได้ชัดว่าอัตราคำขอของคุณสูงเกินไปและเซิร์ฟเวอร์ไม่เต็มใจที่จะยอมรับสิ่งนี้

คุณไม่ควรพยายาม "หลบเลี่ยง" สิ่งนี้หรือแม้แต่พยายามหลีกเลี่ยงการตั้งค่าความปลอดภัยของเซิร์ฟเวอร์โดยพยายามปลอมแปลง IP ของคุณคุณควรเคารพคำตอบของเซิร์ฟเวอร์โดยไม่ส่งคำขอมากเกินไป

หากตั้งค่าทุกอย่างถูกต้องคุณจะได้รับส่วนหัว "ลองอีกครั้ง" พร้อมกับคำตอบ 429 ส่วนหัวนี้ระบุจำนวนวินาทีที่คุณควรรอก่อนโทรออกอีกครั้ง วิธีที่เหมาะสมในการจัดการกับ "ปัญหา" นี้คือการอ่านส่วนหัวนี้และหยุดกระบวนการของคุณเป็นเวลาหลายวินาที

คุณสามารถค้นหาข้อมูลเพิ่มเติมเกี่ยวกับสถานะ 429 ได้ที่นี่: http://tools.ietf.org/html/rfc6585#page-3


23
ไม่มีใครเคยบอกว่าเว็บเซิร์ฟเวอร์ทั้งหมดได้รับการกำหนดค่าอย่างถูกต้อง นอกจากนี้เนื่องจากตัว จำกัด อัตราส่วนใหญ่ระบุผู้เข้าชมด้วย IP จึงอาจทำให้เกิดปัญหาในสถานการณ์ที่มีการแชร์ IP แบบไดนามิก หากคุณยังคงได้รับสถานะ 429 แม้ว่าคุณจะมั่นใจว่าไม่ได้ส่งคำขอมากเกินไปเลยก็ตามคุณอาจลองติดต่อผู้ดูแลระบบของไซต์
MRA

2
ขอขอบคุณที่กล่าวถึงส่วนหัว "Retry-after" ฉันชอบตัวอย่างโค้ดเพื่อดูวิธีรับค่านั้น (ฉันใช้ urllib เพื่อใช้กลไก OP ไม่ว่าในกรณีใดฉันไม่คิดว่าส่วนหัวจะรวมอยู่ในข้อยกเว้นที่เพิ่มขึ้น)
MacFreek

@MacFreek ฉันไม่มีตัวอย่างโค้ด Python โดยเฉพาะ แต่ฉันคิดว่าตัวอย่างบางส่วนเกี่ยวกับวิธีดึงส่วนหัวการตอบกลับโดยทั่วไปสามารถนำมาจากคำตอบของคำถามนี้: stackoverflow.com/q/843392
MRA

ขอบคุณ @MRA ฉันพบว่าส่วนหัวมีอยู่ในข้อยกเว้นเช่นกัน: หลังจากจับHTTPError as my_exceptionแล้วก็มีอยู่ในmy_exception.headersurllib2 เป็นอย่างน้อย
MacFreek

38

การเขียนโค้ดชิ้นนี้ช่วยแก้ปัญหาของฉัน:

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


26
คำตอบนี้ถูกลงคะแนน แต่บางไซต์จะส่งคืนรหัสข้อผิดพลาด 429 โดยอัตโนมัติหากตัวแทนผู้ใช้ถูกแบนเนื่องจากการละเมิดจากบุคคลอื่น หากคุณได้รับรหัสข้อผิดพลาด 429 แม้ว่าคุณจะส่งคำขอเพียงไม่กี่คำขอให้ลองตั้งค่าตัวแทนผู้ใช้เป็นอย่างอื่น
เรือเฟอร์รี่ Boender

7
นอกจากนี้ยังต้องการเพิ่มเว็บไซต์บางแห่งปฏิเสธคำขออย่างชัดเจนเว้นแต่ว่าจะมีการส่ง User-agent และคุณอาจได้รับคำตอบอื่น ๆ อีกมากมาย: 503/403 / หน้าดัชนีทั่วไปบางหน้า
user3791372

1
ยืนยันได้เลย. เพียงพยายามเชื่อมต่อ python กับ reddit และไม่ได้ตั้งค่าตัวแทนผู้ใช้ฉันมักจะได้รับรหัสข้อผิดพลาด 429
Karrq

1
ช่วยเพิ่มคำอธิบายได้ไหม
Tokci

คุณ "เขียนโค้ดชิ้นนี้" ที่ไหน? โซลูชันนี้ต้องการรายละเอียดเพิ่มเติม
Joe McLean

30

ดังที่ MRA กล่าวไว้คุณไม่ควรพยายามหลบ429 Too Many Requestsแต่จัดการตามนั้นแทน คุณมีหลายทางเลือกขึ้นอยู่กับกรณีการใช้งานของคุณ:

1) นอนกระบวนการของคุณ โดยปกติเซิร์ฟเวอร์จะมีRetry-afterส่วนหัวในการตอบกลับพร้อมจำนวนวินาทีที่คุณควรรอก่อนที่จะลองใหม่ โปรดทราบว่าการหยุดทำงานของกระบวนการอาจทำให้เกิดปัญหาเช่นในคิวงานซึ่งคุณควรลองทำงานใหม่ในภายหลังเพื่อเพิ่มพื้นที่ว่างให้คนงานทำสิ่งอื่น ๆ

2) แบ็คออฟแบบเอ็กซ์โปเนนเชียล หากเซิร์ฟเวอร์ไม่แจ้งให้คุณทราบว่าต้องรอนานเท่าใดคุณสามารถลองคำขอของคุณอีกครั้งโดยใช้การหยุดเพิ่มขึ้นระหว่าง ขึ้นฉ่ายคิวงานยอดนิยมมีคุณสมบัตินี้ในตัว

3) ถัง Token เทคนิคนี้มีประโยชน์หากคุณทราบล่วงหน้าว่าคุณสามารถร้องขอได้กี่คำขอในเวลาที่กำหนด ทุกครั้งที่คุณเข้าถึง API คุณจะดึงโทเค็นจากที่เก็บข้อมูลเป็นครั้งแรก ถังจะถูกเติมในอัตราคงที่ หากที่เก็บข้อมูลว่างเปล่าคุณจะต้องรอก่อนที่จะกดปุ่ม API อีกครั้ง โดยปกติที่เก็บข้อมูลโทเค็นจะถูกนำไปใช้ในอีกด้านหนึ่ง (API) แต่คุณยังสามารถใช้เป็นพร็อกซีเพื่อหลีกเลี่ยงการได้รับไฟล์429 Too Many Requests. คุณลักษณะrate_limitของคื่นฉ่ายใช้อัลกอริธึมถังโทเค็น

นี่คือตัวอย่างของแอพ Python / Celery ที่ใช้ backoff แบบเอ็กซ์โปเนนเชียลและที่เก็บข้อมูล จำกัด อัตรา / โทเค็น:

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

วิธีแก้ปัญหาอื่นคือการปลอมแปลง IP ของคุณโดยใช้ Public VPN หรือเครือข่าย Tor นี่จะถือว่าเป็นการ จำกัด อัตราบนเซิร์ฟเวอร์ที่ระดับ IP

มีบล็อกโพสต์สั้น ๆ ที่สาธิตวิธีการใช้ tor ร่วมกับ urllib2:

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


9
นี่คือเหตุผลที่ฉันต้องการให้ผู้ใช้ API ของฉันลงทะเบียนคีย์เพื่อส่งคำขออยู่เสมอ ด้วยวิธีนี้ฉันสามารถ จำกัด คำขอด้วยคีย์แทนที่จะเป็น IP การลงทะเบียนสำหรับคีย์อื่นจะเป็นวิธีเดียวที่จะได้รับขีด จำกัด ที่สูงขึ้น
Mnebuerquo


2

ฉันพบวิธีแก้ปัญหาที่ดีในการบล็อก IPเมื่อคัดลอกไซต์ ช่วยให้คุณสามารถเรียกใช้ Scraper ได้อย่างไม่มีกำหนดโดยเรียกใช้จาก Google App Engine และปรับใช้ใหม่โดยอัตโนมัติเมื่อคุณได้รับ 429

ลองอ่านบทความนี้


ฮ่าฮ่าว้าว ... ใช้กูเกิลขูด Google จากนั้นเปลี่ยน Google IP ของคุณเมื่อ Google บล็อก
sam1370
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.