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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24518944/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 04:43:56  来源:igfitidea点击:

Try/except when using Python requests module

pythonpython-requeststry-except

提问by mroriel

Doing some API testing and trying to create a function that given an inputted URL it will return the json response, however if a HTTP error is the response an error message will be returned.

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

I was using urllib2 before, but now trying to use requests instead. However it looks like my except block is never executed, regardless of the error.

我之前使用 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)

The result I get from running the above...

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

<Response [404]>

采纳答案by Ian Stapleton Cordasco

If you want the response to raise an exception for a non-200 status code use response.raise_for_status(). Your code would then look like:

如果您希望响应引发非 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

You can tell that this is clearly simpler than the other solutions here and doesn't require you to check the status code manually. You would also just catch an HTTPErrorsince that is what raise_for_statuswill raise. Catching RequestsExceptionis a poor idea. That will catch things like ConnectionErrors or TimeoutErrors, etc. None of those mean the same thing as what you're trying to catch.

您可以看出这显然比此处的其他解决方案更简单,并且不需要您手动检查状态代码。你也会抓住一个,HTTPError因为那是raise_for_status会引起的。捕捉RequestsException是一个坏主意。这将捕获诸如ConnectionErrors 或TimeoutErrors 之类的东西。这些都与您要捕获的含义不同。

回答by austin

You can check the response.status_codevalue. If it's not 200, then you can consider it to be an error condition and throw your own exception.

您可以检查该response.status_code值。如果不是200,那么您可以将其视为错误条件并抛出您自己的异常。

回答by Lukas Graf

Note: You should rather go with response.raise_for_status()as described in Ian's answerabove (he's one of the maintainers of the requestsmodule).

注意:您应该response.raise_for_status()按照上面Ian 的回答中的描述进行操作(他是该requests模块的维护者之一)。



How you handle this all depends on what you consider an HTTP error. There's status codes, but not everything other than 200necessarily means there's an error of some sort.

您如何处理这一切取决于您认为 HTTP 错误是什么。有状态代码,但并非所有其他内容都200意味着存在某种错误。

As you noticed, the request library considers those just another aspect of a HTTP response and doesn't raise an exception. HTTP status 302for example means Found, but the response doesn't contain a response body but a Locationheader instead that you'd need to follow to get to the resource you actually wanted.

正如您所注意到的,请求库只考虑 HTTP 响应的另一个方面,不会引发异常。302例如Found,HTTP 状态意味着,但响应不包含响应正文,而是包含一个Location标头,您需要遵循该标头才能访问您实际想要的资源。

So you'll want to look at response.status_code, and do your handling of that, while catching actual protocol errorswith a try..except. When catching those you should actually catch requests.exceptions.RequestException, because this is the base class for all other exceptionsthe requestsmodule raises.

所以你想看看response.status_code,做你的是操控性,同时捕捉实际协议错误try..except。当捕获那些你应该真正捕获的时候requests.exceptions.RequestException,因为这是模块引发的所有其他异常基类requests

So here's an example that demonstrates all three cases:

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

  • Sucessfull 200 OKresponse
  • Sucessful request and response, but status other than 200
  • Protocol error (invalid schema)
  • 成功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

Output:

输出:

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'

There could also be an exception raised by response.json()if you get a sucessfull response, but it simply isn't JSON - so you might want to account for that as well.

response.json()如果您收到成功的响应,也可能会引发异常,但它根本不是 JSON - 所以您可能也需要考虑到这一点。



Note: The if not response.status_code // 100 == 2bit works like this: The //operator does a so called floor division, so it rounds down to the next integer (this is the default behavior for the /in Python 2.x, but not Python 3.x, which changed /to do floating point division). So status // 100 == 2holds true for all 2xxcodes.

注意:该if not response.status_code // 100 == 2位的工作方式如下://运算符执行所谓的floor 除法,因此它向下舍入到下一个整数(这是/Python 2.x 中的默认行为,但不是 Python 3.x,它更改/为浮点除法)。因此status // 100 == 2适用于所有2xx代码。