使用Python请求模块时尝试/除外

mro*_*iel 18 python try-except python-requests

做一些API测试并尝试创建一个给定输入URL的函数它将返回json响应,但是如果HTTP错误是响应,则将返回错误消息.

我之前使用的是urllib2,但现在尝试使用请求.但是看起来我的except块永远不会被执行,无论错误如何.

testURL = 'http://httpbin.org/status/404'


def return_json(URL):
    try:
        response = requests.get(URL)
        json_obj = response.json()
        return json_obj
    except requests.exceptions.HTTPError as e:
        return "Error: " + str(e)
Run Code Online (Sandbox Code Playgroud)

我从运行上面得到的结果......

<Response [404]>
Run Code Online (Sandbox Code Playgroud)

Ian*_*sco 32

如果您希望响应为非200状态代码使用引发异常response.raise_for_status().您的代码将如下所示:

testURL = 'http://httpbin.org/status/404'


def return_json(URL):
    response = requests.get(testURL)

    try:
        response.raise_for_status()
    except requests.exceptions.HTTPError as e:
        # Whoops it wasn't a 200
        return "Error: " + str(e)

    # Must have been a 200 status code
    json_obj = response.json()
    return json_obj
Run Code Online (Sandbox Code Playgroud)

您可以看出这显然比其他解决方案简单,并且不需要您手动检查状态代码.你也会抓住一个,HTTPError因为那raise_for_status将是什么.捕捉RequestsException是一个糟糕的主意.那会抓住像ConnectionErrors或TimeoutErrors等东西.这些都不是你想要抓住的东西.


Luk*_*raf 11

注意:尽管这是可以接受的答案,但您应该response.raise_for_status()按照Ian的答案中所述(他是该requests模块的维护者之一).


如何处理这一切取决于您认为HTTP错误.有状态代码,但除了200必然意味着某种错误之外的所有事情都不是.

正如您所注意到的,请求库仅将这些视为HTTP响应的另一个方面,并且不会引发异常.302例如Found,HTTP状态意味着,但响应不包含响应正文,而是包含一个Location标题,而不是您需要遵循以获取您实际想要的资源.

因此,您需要查看response.status_code并对其进行处理,同时使用a 捕获实际的协议错误try..except.捕获那些你应该捕获的那些requests.exceptions.RequestException,因为这是模块引发的所有其他异常基类requests.

所以这是一个演示所有三种情况的例子:

  • 成功200 OK回应
  • 成功的请求和响应,但状态除外 200
  • 协议错误(架构无效)
import requests

test_urls = ['http://httpbin.org/user-agent',
             'http://httpbin.org/status/404',
             'http://httpbin.org/status/500',
             'httpx://invalid/url']


def return_json(url):
    try:
        response = requests.get(url)

        # Consider any status other than 2xx an error
        if not response.status_code // 100 == 2:
            return "Error: Unexpected response {}".format(response)

        json_obj = response.json()
        return json_obj
    except requests.exceptions.RequestException as e:
        # A serious problem happened, like an SSLError or InvalidURL
        return "Error: {}".format(e)


for url in test_urls:
    print "Fetching URL '{}'".format(url)
    print return_json(url)
    print
Run Code Online (Sandbox Code Playgroud)

输出:

Fetching URL 'http://httpbin.org/user-agent'
{u'user-agent': u'python-requests/2.1.0 CPython/2.7.1 Darwin/11.4.2'}

Fetching URL 'http://httpbin.org/status/404'
Error: Unexpected response <Response [404]>

Fetching URL 'http://httpbin.org/status/500'
Error: Unexpected response <Response [500]>

Fetching URL 'httpx://invalid/url'
Error: No connection adapters were found for 'httpx://invalid/url'
Run Code Online (Sandbox Code Playgroud)

response.json()如果你得到一个成功的回复,也可能会有一个例外,但它根本就不是JSON - 所以你也可能想要考虑到这一点.


:该if not response.status_code // 100 == 2位是这样的:在//运营商做了所谓的楼层划分,因此它向下取整为下一个整数(这是对的默认行为/在Python 2.x的,但不是Python的3.x中,从而改变/做浮点师).因此status // 100 == 2适用于所有2xx代码.