วิธีที่ถูกต้องในการลอง / ยกเว้นการใช้โมดูล Python ร้องขอ?


418
try:
    r = requests.get(url, params={'s': thing})
except requests.ConnectionError, e:
    print e #should I also sys.exit(1) after this?

ถูกต้องหรือไม่ มีวิธีที่ดีกว่าในการจัดโครงสร้างสิ่งนี้หรือไม่? สิ่งนี้จะครอบคลุมฐานทั้งหมดของฉันหรือไม่


คำตอบ:


794

มีลักษณะที่ร้องขอเอกสารข้อยกเว้น ในระยะสั้น:

ในกรณีที่เกิดปัญหาเครือข่าย (เช่น DNS ล้มเหลวปฏิเสธการเชื่อมต่อ ฯลฯ ) คำขอจะเพิ่มConnectionErrorข้อยกเว้น

ในกรณีที่การตอบสนอง HTTP ที่ไม่ถูกต้องหายากคำขอจะเพิ่มHTTPErrorข้อยกเว้น

หากคำขอหมดเวลาจะมีTimeoutข้อยกเว้นเกิดขึ้น

หากคำขอเกินจำนวนการเปลี่ยนเส้นทางสูงสุดที่กำหนดไว้TooManyRedirectsจะมีการยกข้อยกเว้น

requests.exceptions.RequestExceptionข้อยกเว้นทั้งหมดที่จองอย่างชัดเจนยกมรดกจาก

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

สิ่งที่ต้องทำเมื่อคุณตรวจพบข้อยกเว้นนั้นขึ้นอยู่กับการออกแบบของสคริปต์ / โปรแกรมของคุณ สามารถออกได้หรือไม่? คุณสามารถไปลองอีกครั้งได้ไหม? หากข้อผิดพลาดเป็นความหายนะและคุณไม่สามารถดำเนินการต่อได้คุณอาจยกเลิกโปรแกรมของคุณโดยเพิ่มSystemExit (เป็นวิธีที่ดีในการพิมพ์ข้อผิดพลาดและการโทรsys.exit)

คุณสามารถตรวจจับข้อยกเว้นระดับฐานซึ่งจะจัดการทุกกรณี:

try:
    r = requests.get(url, params={'s': thing})
except requests.exceptions.RequestException as e:  # This is the correct syntax
    raise SystemExit(e)

หรือคุณสามารถจับมันแยกจากกันและทำสิ่งต่าง ๆ

try:
    r = requests.get(url, params={'s': thing})
except requests.exceptions.Timeout:
    # Maybe set up for a retry, or continue in a retry loop
except requests.exceptions.TooManyRedirects:
    # Tell the user their URL was bad and try a different one
except requests.exceptions.RequestException as e:
    # catastrophic error. bail.
    raise SystemExit(e)

ดังที่คริสเตียนชี้ให้เห็น:

หากคุณต้องการข้อผิดพลาด http (เช่น 401 Unauthorized) เพื่อเพิ่มข้อยกเว้นคุณสามารถโทรResponse.raise_for_statusได้ ที่จะยกHTTPErrorถ้าการตอบสนองข้อผิดพลาด http

ตัวอย่าง:

try:
    r = requests.get('http://www.google.com/nothere')
    r.raise_for_status()
except requests.exceptions.HTTPError as err:
    raise SystemExit(err)

จะพิมพ์:

404 Client Error: Not Found for url: http://www.google.com/nothere

11
คำตอบที่ดีมากสำหรับการจัดการกับไลบรารีเฉพาะคำขอและข้อยกเว้นทั่วไป
Brian Peterson

10
โปรดทราบว่าเนื่องจากข้อผิดพลาดในไลบรารี urllib3 ที่มีการขีดเส้นใต้คุณจะต้องตรวจสอบsocket.timeoutข้อยกเว้นหากคุณใช้หมดเวลา: github.com/kennethreitz/requests/issues/1236
jb

15
ผู้อ่านความคิดเห็นในอนาคต: สิ่งนี้ได้รับการแก้ไขในคำขอ 2.9 (ซึ่งรวมกลุ่ม urllib3 1.13)
RazerM

14
หากคุณต้องการ http ข้อผิดพลาด (เช่น 401 ไม่ได้รับอนุญาต) เพื่อเพิ่มข้อยกเว้นคุณสามารถเรียกResponse.raise_for_status ที่จะเพิ่ม HTTPError หากการตอบสนองเป็นข้อผิดพลาด http
คริสเตียน

5
รายการข้อยกเว้นบนเว็บไซต์ขอไม่สมบูรณ์ คุณสามารถอ่านรายการเต็มรูปแบบที่นี่
Epoc

87

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

url='http://www.google.com/blahblah'

try:
    r = requests.get(url,timeout=3)
    r.raise_for_status()
except requests.exceptions.HTTPError as errh:
    print ("Http Error:",errh)
except requests.exceptions.ConnectionError as errc:
    print ("Error Connecting:",errc)
except requests.exceptions.Timeout as errt:
    print ("Timeout Error:",errt)
except requests.exceptions.RequestException as err:
    print ("OOps: Something Else",err)

Http Error: 404 Client Error: Not Found for url: http://www.google.com/blahblah

VS

url='http://www.google.com/blahblah'

try:
    r = requests.get(url,timeout=3)
    r.raise_for_status()
except requests.exceptions.RequestException as err:
    print ("OOps: Something Else",err)
except requests.exceptions.HTTPError as errh:
    print ("Http Error:",errh)
except requests.exceptions.ConnectionError as errc:
    print ("Error Connecting:",errc)
except requests.exceptions.Timeout as errt:
    print ("Timeout Error:",errt)     

OOps: Something Else 404 Client Error: Not Found for url: http://www.google.com/blahblah

นี่เป็นไวยากรณ์ที่ถูกต้องสำหรับการโพสต์ด้วยหรือไม่
ScipioAfricanus

@ScipioAfricanus ใช่
andrea

10

วัตถุข้อยกเว้นยังประกอบด้วยการตอบกลับดั้งเดิมe.responseซึ่งอาจมีประโยชน์หากต้องการดูเนื้อหาของข้อผิดพลาดในการตอบสนองจากเซิร์ฟเวอร์ ตัวอย่างเช่น:

try:
    r = requests.post('somerestapi.com/post-here', data={'birthday': '9/9/3999'})
    r.raise_for_status()
except requests.exceptions.HTTPError as e:
    print (e.response.text)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.