Python request http error

A simple, yet elegant, HTTP library. Contribute to psf/requests development by creating an account on GitHub.
.. module:: requests.models

Eager to get started? This page gives a good introduction in how to get started
with Requests.

First, make sure that:

  • Requests is :ref:`installed <install>`
  • Requests is :ref:`up-to-date <updates>`

Let’s get started with some simple examples.

Make a Request

Making a request with Requests is very simple.

Begin by importing the Requests module:

>>> import requests

Now, let’s try to get a webpage. For this example, let’s get GitHub’s public
timeline:

>>> r = requests.get('https://api.github.com/events')

Now, we have a :class:`Response <requests.Response>` object called r. We can
get all the information we need from this object.

Requests’ simple API means that all forms of HTTP request are as obvious. For
example, this is how you make an HTTP POST request:

>>> r = requests.post('https://httpbin.org/post', data={'key': 'value'})

Nice, right? What about the other HTTP request types: PUT, DELETE, HEAD and
OPTIONS? These are all just as simple:

>>> r = requests.put('https://httpbin.org/put', data={'key': 'value'})
>>> r = requests.delete('https://httpbin.org/delete')
>>> r = requests.head('https://httpbin.org/get')
>>> r = requests.options('https://httpbin.org/get')

That’s all well and good, but it’s also only the start of what Requests can
do.

Passing Parameters In URLs

You often want to send some sort of data in the URL’s query string. If
you were constructing the URL by hand, this data would be given as key/value
pairs in the URL after a question mark, e.g. httpbin.org/get?key=val.
Requests allows you to provide these arguments as a dictionary of strings,
using the params keyword argument. As an example, if you wanted to pass
key1=value1 and key2=value2 to httpbin.org/get, you would use the
following code:

>>> payload = {'key1': 'value1', 'key2': 'value2'}
>>> r = requests.get('https://httpbin.org/get', params=payload)

You can see that the URL has been correctly encoded by printing the URL:

>>> print(r.url)
https://httpbin.org/get?key2=value2&key1=value1

Note that any dictionary key whose value is None will not be added to the
URL’s query string.

You can also pass a list of items as a value:

>>> payload = {'key1': 'value1', 'key2': ['value2', 'value3']}

>>> r = requests.get('https://httpbin.org/get', params=payload)
>>> print(r.url)
https://httpbin.org/get?key1=value1&key2=value2&key2=value3

Response Content

We can read the content of the server’s response. Consider the GitHub timeline
again:

>>> import requests

>>> r = requests.get('https://api.github.com/events')
>>> r.text
'[{"repository":{"open_issues":0,"url":"https://github.com/...

Requests will automatically decode content from the server. Most unicode
charsets are seamlessly decoded.

When you make a request, Requests makes educated guesses about the encoding of
the response based on the HTTP headers. The text encoding guessed by Requests
is used when you access r.text. You can find out what encoding Requests is
using, and change it, using the r.encoding property:

>>> r.encoding
'utf-8'
>>> r.encoding = 'ISO-8859-1'

If you change the encoding, Requests will use the new value of r.encoding
whenever you call r.text. You might want to do this in any situation where
you can apply special logic to work out what the encoding of the content will
be. For example, HTML and XML have the ability to specify their encoding in
their body. In situations like this, you should use r.content to find the
encoding, and then set r.encoding. This will let you use r.text with
the correct encoding.

Requests will also use custom encodings in the event that you need them. If
you have created your own encoding and registered it with the codecs
module, you can simply use the codec name as the value of r.encoding and
Requests will handle the decoding for you.

Binary Response Content

You can also access the response body as bytes, for non-text requests:

>>> r.content
b'[{"repository":{"open_issues":0,"url":"https://github.com/...

The gzip and deflate transfer-encodings are automatically decoded for you.

The br transfer-encoding is automatically decoded for you if a Brotli library
like brotli or brotlicffi is installed.

For example, to create an image from binary data returned by a request, you can
use the following code:

>>> from PIL import Image
>>> from io import BytesIO

>>> i = Image.open(BytesIO(r.content))

JSON Response Content

There’s also a builtin JSON decoder, in case you’re dealing with JSON data:

>>> import requests

>>> r = requests.get('https://api.github.com/events')
>>> r.json()
[{'repository': {'open_issues': 0, 'url': 'https://github.com/...

In case the JSON decoding fails, r.json() raises an exception. For example, if
the response gets a 204 (No Content), or if the response contains invalid JSON,
attempting r.json() raises requests.exceptions.JSONDecodeError. This wrapper exception
provides interoperability for multiple exceptions that may be thrown by different
python versions and json serialization libraries.

It should be noted that the success of the call to r.json() does not
indicate the success of the response. Some servers may return a JSON object in a
failed response (e.g. error details with HTTP 500). Such JSON will be decoded
and returned. To check that a request is successful, use
r.raise_for_status() or check r.status_code is what you expect.

Raw Response Content

In the rare case that you’d like to get the raw socket response from the
server, you can access r.raw. If you want to do this, make sure you set
stream=True in your initial request. Once you do, you can do this:

>>> r = requests.get('https://api.github.com/events', stream=True)

>>> r.raw
<urllib3.response.HTTPResponse object at 0x101194810>

>>> r.raw.read(10)
'x1fx8bx08x00x00x00x00x00x00x03'

In general, however, you should use a pattern like this to save what is being
streamed to a file:

with open(filename, 'wb') as fd:
    for chunk in r.iter_content(chunk_size=128):
        fd.write(chunk)

Using Response.iter_content will handle a lot of what you would otherwise
have to handle when using Response.raw directly. When streaming a
download, the above is the preferred and recommended way to retrieve the
content. Note that chunk_size can be freely adjusted to a number that
may better fit your use cases.

Note

An important note about using Response.iter_content versus Response.raw.
Response.iter_content will automatically decode the gzip and deflate
transfer-encodings. Response.raw is a raw stream of bytes — it does not
transform the response content. If you really need access to the bytes as they
were returned, use Response.raw.

Custom Headers

If you’d like to add HTTP headers to a request, simply pass in a dict to the
headers parameter.

For example, we didn’t specify our user-agent in the previous example:

>>> url = 'https://api.github.com/some/endpoint'
>>> headers = {'user-agent': 'my-app/0.0.1'}

>>> r = requests.get(url, headers=headers)

Note: Custom headers are given less precedence than more specific sources of information. For instance:

  • Authorization headers set with headers= will be overridden if credentials
    are specified in .netrc, which in turn will be overridden by the auth=
    parameter. Requests will search for the netrc file at ~/.netrc, ~/_netrc,
    or at the path specified by the NETRC environment variable.
  • Authorization headers will be removed if you get redirected off-host.
  • Proxy-Authorization headers will be overridden by proxy credentials provided in the URL.
  • Content-Length headers will be overridden when we can determine the length of the content.

Furthermore, Requests does not change its behavior at all based on which custom headers are specified. The headers are simply passed on into the final request.

Note: All header values must be a string, bytestring, or unicode. While permitted, it’s advised to avoid passing unicode header values.

More complicated POST requests

Typically, you want to send some form-encoded data — much like an HTML form.
To do this, simply pass a dictionary to the data argument. Your
dictionary of data will automatically be form-encoded when the request is made:

>>> payload = {'key1': 'value1', 'key2': 'value2'}

>>> r = requests.post("https://httpbin.org/post", data=payload)
>>> print(r.text)
{
  ...
  "form": {
    "key2": "value2",
    "key1": "value1"
  },
  ...
}

The data argument can also have multiple values for each key. This can be
done by making data either a list of tuples or a dictionary with lists
as values. This is particularly useful when the form has multiple elements that
use the same key:

>>> payload_tuples = [('key1', 'value1'), ('key1', 'value2')]
>>> r1 = requests.post('https://httpbin.org/post', data=payload_tuples)
>>> payload_dict = {'key1': ['value1', 'value2']}
>>> r2 = requests.post('https://httpbin.org/post', data=payload_dict)
>>> print(r1.text)
{
  ...
  "form": {
    "key1": [
      "value1",
      "value2"
    ]
  },
  ...
}
>>> r1.text == r2.text
True

There are times that you may want to send data that is not form-encoded. If
you pass in a string instead of a dict, that data will be posted directly.

For example, the GitHub API v3 accepts JSON-Encoded POST/PATCH data:

>>> import json

>>> url = 'https://api.github.com/some/endpoint'
>>> payload = {'some': 'data'}

>>> r = requests.post(url, data=json.dumps(payload))

Please note that the above code will NOT add the Content-Type header
(so in particular it will NOT set it to application/json).

If you need that header set and you don’t want to encode the dict yourself,
you can also pass it directly using the json parameter (added in version 2.4.2)
and it will be encoded automatically:

>>> url = 'https://api.github.com/some/endpoint'
>>> payload = {'some': 'data'}
>>> r = requests.post(url, json=payload)

Note, the json parameter is ignored if either data or files is passed.

POST a Multipart-Encoded File

Requests makes it simple to upload Multipart-encoded files:

>>> url = 'https://httpbin.org/post'
>>> files = {'file': open('report.xls', 'rb')}

>>> r = requests.post(url, files=files)
>>> r.text
{
  ...
  "files": {
    "file": "<censored...binary...data>"
  },
  ...
}

You can set the filename, content_type and headers explicitly:

>>> url = 'https://httpbin.org/post'
>>> files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})}

>>> r = requests.post(url, files=files)
>>> r.text
{
  ...
  "files": {
    "file": "<censored...binary...data>"
  },
  ...
}

If you want, you can send strings to be received as files:

>>> url = 'https://httpbin.org/post'
>>> files = {'file': ('report.csv', 'some,data,to,sendnanother,row,to,sendn')}

>>> r = requests.post(url, files=files)
>>> r.text
{
  ...
  "files": {
    "file": "some,data,to,send\nanother,row,to,send\n"
  },
  ...
}

In the event you are posting a very large file as a multipart/form-data
request, you may want to stream the request. By default, requests does not
support this, but there is a separate package which does —
requests-toolbelt. You should read the toolbelt’s documentation for more details about how to use it.

For sending multiple files in one request refer to the :ref:`advanced <advanced>`
section.

Warning

It is strongly recommended that you open files in :ref:`binary
mode <tut-files>`
. This is because Requests may attempt to provide
the Content-Length header for you, and if it does this value
will be set to the number of bytes in the file. Errors may occur
if you open the file in text mode.

Response Status Codes

We can check the response status code:

>>> r = requests.get('https://httpbin.org/get')
>>> r.status_code
200

Requests also comes with a built-in status code lookup object for easy
reference:

>>> r.status_code == requests.codes.ok
True

If we made a bad request (a 4XX client error or 5XX server error response), we
can raise it with
:meth:`Response.raise_for_status() <requests.Response.raise_for_status>`:

>>> bad_r = requests.get('https://httpbin.org/status/404')
>>> bad_r.status_code
404

>>> bad_r.raise_for_status()
Traceback (most recent call last):
  File "requests/models.py", line 832, in raise_for_status
    raise http_error
requests.exceptions.HTTPError: 404 Client Error

But, since our status_code for r was 200, when we call
raise_for_status() we get:

>>> r.raise_for_status()
None

All is well.

Response Headers

We can view the server’s response headers using a Python dictionary:

>>> r.headers
{
    'content-encoding': 'gzip',
    'transfer-encoding': 'chunked',
    'connection': 'close',
    'server': 'nginx/1.0.4',
    'x-runtime': '148ms',
    'etag': '"e1ca502697e5c9317743dc078f67693f"',
    'content-type': 'application/json'
}

The dictionary is special, though: it’s made just for HTTP headers. According to
RFC 7230, HTTP Header names
are case-insensitive.

So, we can access the headers using any capitalization we want:

>>> r.headers['Content-Type']
'application/json'

>>> r.headers.get('content-type')
'application/json'

It is also special in that the server could have sent the same header multiple
times with different values, but requests combines them so they can be
represented in the dictionary within a single mapping, as per
RFC 7230:

A recipient MAY combine multiple header fields with the same field name
into one «field-name: field-value» pair, without changing the semantics
of the message, by appending each subsequent field value to the combined
field value in order, separated by a comma.

Cookies

If a response contains some Cookies, you can quickly access them:

>>> url = 'http://example.com/some/cookie/setting/url'
>>> r = requests.get(url)

>>> r.cookies['example_cookie_name']
'example_cookie_value'

To send your own cookies to the server, you can use the cookies
parameter:

>>> url = 'https://httpbin.org/cookies'
>>> cookies = dict(cookies_are='working')

>>> r = requests.get(url, cookies=cookies)
>>> r.text
'{"cookies": {"cookies_are": "working"}}'

Cookies are returned in a :class:`~requests.cookies.RequestsCookieJar`,
which acts like a dict but also offers a more complete interface,
suitable for use over multiple domains or paths. Cookie jars can
also be passed in to requests:

>>> jar = requests.cookies.RequestsCookieJar()
>>> jar.set('tasty_cookie', 'yum', domain='httpbin.org', path='/cookies')
>>> jar.set('gross_cookie', 'blech', domain='httpbin.org', path='/elsewhere')
>>> url = 'https://httpbin.org/cookies'
>>> r = requests.get(url, cookies=jar)
>>> r.text
'{"cookies": {"tasty_cookie": "yum"}}'

Redirection and History

By default Requests will perform location redirection for all verbs except
HEAD.

We can use the history property of the Response object to track redirection.

The :attr:`Response.history <requests.Response.history>` list contains the
:class:`Response <requests.Response>` objects that were created in order to
complete the request. The list is sorted from the oldest to the most recent
response.

For example, GitHub redirects all HTTP requests to HTTPS:

>>> r = requests.get('http://github.com/')

>>> r.url
'https://github.com/'

>>> r.status_code
200

>>> r.history
[<Response [301]>]

If you’re using GET, OPTIONS, POST, PUT, PATCH or DELETE, you can disable
redirection handling with the allow_redirects parameter:

>>> r = requests.get('http://github.com/', allow_redirects=False)

>>> r.status_code
301

>>> r.history
[]

If you’re using HEAD, you can enable redirection as well:

>>> r = requests.head('http://github.com/', allow_redirects=True)

>>> r.url
'https://github.com/'

>>> r.history
[<Response [301]>]

Timeouts

You can tell Requests to stop waiting for a response after a given number of
seconds with the timeout parameter. Nearly all production code should use
this parameter in nearly all requests. Failure to do so can cause your program
to hang indefinitely:

>>> requests.get('https://github.com/', timeout=0.001)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
requests.exceptions.Timeout: HTTPConnectionPool(host='github.com', port=80): Request timed out. (timeout=0.001)

Note

timeout is not a time limit on the entire response download;
rather, an exception is raised if the server has not issued a
response for timeout seconds (more precisely, if no bytes have been
received on the underlying socket for timeout seconds). If no timeout is specified explicitly, requests do
not time out.

Errors and Exceptions

In the event of a network problem (e.g. DNS failure, refused connection, etc),
Requests will raise a :exc:`~requests.exceptions.ConnectionError` exception.

:meth:`Response.raise_for_status() <requests.Response.raise_for_status>` will
raise an :exc:`~requests.exceptions.HTTPError` if the HTTP request
returned an unsuccessful status code.

If a request times out, a :exc:`~requests.exceptions.Timeout` exception is
raised.

If a request exceeds the configured number of maximum redirections, a
:exc:`~requests.exceptions.TooManyRedirects` exception is raised.

All exceptions that Requests explicitly raises inherit from
:exc:`requests.exceptions.RequestException`.


Ready for more? Check out the :ref:`advanced <advanced>` section.

If you’re on the job market, consider taking this programming quiz. A substantial donation will be made to this project, if you find a job through this platform.

This part of the documentation covers all the interfaces of Requests. For
parts where Requests depends on external libraries, we document the most
important right here and provide links to the canonical documentation.

Main Interface¶

All of Requests’ functionality can be accessed by these 7 methods.
They all return an instance of the Response object.

requests.request(method, url, **kwargs)[source]

Constructs and sends a Request.

Parameters:
  • method – method for the new Request object.
  • url – URL for the new Request object.
  • params – (optional) Dictionary, list of tuples or bytes to send
    in the body of the Request.
  • data – (optional) Dictionary, list of tuples, bytes, or file-like
    object to send in the body of the Request.
  • json – (optional) A JSON serializable Python object to send in the body of the Request.
  • headers – (optional) Dictionary of HTTP Headers to send with the Request.
  • cookies – (optional) Dict or CookieJar object to send with the Request.
  • files – (optional) Dictionary of 'name': file-like-objects (or {'name': file-tuple}) for multipart encoding upload.
    file-tuple can be a 2-tuple ('filename', fileobj), 3-tuple ('filename', fileobj, 'content_type')
    or a 4-tuple ('filename', fileobj, 'content_type', custom_headers), where 'content-type' is a string
    defining the content type of the given file and custom_headers a dict-like object containing additional headers
    to add for the file.
  • auth – (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth.
  • timeout (float or tuple) – (optional) How many seconds to wait for the server to send data
    before giving up, as a float, or a (connect timeout, read
    timeout)
    tuple.
  • allow_redirects (bool) – (optional) Boolean. Enable/disable GET/OPTIONS/POST/PUT/PATCH/DELETE/HEAD redirection. Defaults to True.
  • proxies – (optional) Dictionary mapping protocol to the URL of the proxy.
  • verify – (optional) Either a boolean, in which case it controls whether we verify
    the server’s TLS certificate, or a string, in which case it must be a path
    to a CA bundle to use. Defaults to True.
  • stream – (optional) if False, the response content will be immediately downloaded.
  • cert – (optional) if String, path to ssl client cert file (.pem). If Tuple, (‘cert’, ‘key’) pair.
Returns:

Response object

Return type:

requests.Response

Usage:

>>> import requests
>>> req = requests.request('GET', 'https://httpbin.org/get')
<Response [200]>
requests.head(url, **kwargs)[source]

Sends a HEAD request.

Parameters:
  • url – URL for the new Request object.
  • **kwargs – Optional arguments that request takes.
Returns:

Response object

Return type:

requests.Response

requests.get(url, params=None, **kwargs)[source]

Sends a GET request.

Parameters:
  • url – URL for the new Request object.
  • params – (optional) Dictionary, list of tuples or bytes to send
    in the body of the Request.
  • **kwargs – Optional arguments that request takes.
Returns:

Response object

Return type:

requests.Response

requests.post(url, data=None, json=None, **kwargs)[source]

Sends a POST request.

Parameters:
  • url – URL for the new Request object.
  • data – (optional) Dictionary, list of tuples, bytes, or file-like
    object to send in the body of the Request.
  • json – (optional) json data to send in the body of the Request.
  • **kwargs – Optional arguments that request takes.
Returns:

Response object

Return type:

requests.Response

requests.put(url, data=None, **kwargs)[source]

Sends a PUT request.

Parameters:
  • url – URL for the new Request object.
  • data – (optional) Dictionary, list of tuples, bytes, or file-like
    object to send in the body of the Request.
  • json – (optional) json data to send in the body of the Request.
  • **kwargs – Optional arguments that request takes.
Returns:

Response object

Return type:

requests.Response

requests.patch(url, data=None, **kwargs)[source]

Sends a PATCH request.

Parameters:
  • url – URL for the new Request object.
  • data – (optional) Dictionary, list of tuples, bytes, or file-like
    object to send in the body of the Request.
  • json – (optional) json data to send in the body of the Request.
  • **kwargs – Optional arguments that request takes.
Returns:

Response object

Return type:

requests.Response

requests.delete(url, **kwargs)[source]

Sends a DELETE request.

Parameters:
  • url – URL for the new Request object.
  • **kwargs – Optional arguments that request takes.
Returns:

Response object

Return type:

requests.Response

Exceptions¶

exception requests.RequestException(*args, **kwargs)[source]

There was an ambiguous exception that occurred while handling your
request.

exception requests.ConnectionError(*args, **kwargs)[source]

A Connection error occurred.

exception requests.HTTPError(*args, **kwargs)[source]

An HTTP error occurred.

exception requests.URLRequired(*args, **kwargs)[source]

A valid URL is required to make a request.

exception requests.TooManyRedirects(*args, **kwargs)[source]

Too many redirects.

exception requests.ConnectTimeout(*args, **kwargs)[source]

The request timed out while trying to connect to the remote server.

Requests that produced this error are safe to retry.

exception requests.ReadTimeout(*args, **kwargs)[source]

The server did not send any data in the allotted amount of time.

exception requests.Timeout(*args, **kwargs)[source]

The request timed out.

Catching this error will catch both
ConnectTimeout and
ReadTimeout errors.

Request Sessions¶

class requests.Session[source]

A Requests session.

Provides cookie persistence, connection-pooling, and configuration.

Basic Usage:

>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
<Response [200]>

Or as a context manager:

>>> with requests.Session() as s:
>>>     s.get('https://httpbin.org/get')
<Response [200]>
auth = None

Default Authentication tuple or object to attach to
Request.

cert = None

SSL client certificate default, if String, path to ssl client
cert file (.pem). If Tuple, (‘cert’, ‘key’) pair.

close()[source]

Closes all adapters and as such the session

cookies = None

A CookieJar containing all currently outstanding cookies set on this
session. By default it is a
RequestsCookieJar, but
may be any other cookielib.CookieJar compatible object.

delete(url, **kwargs)[source]

Sends a DELETE request. Returns Response object.

Parameters:
  • url – URL for the new Request object.
  • **kwargs – Optional arguments that request takes.
Return type:

requests.Response

get(url, **kwargs)[source]

Sends a GET request. Returns Response object.

Parameters:
  • url – URL for the new Request object.
  • **kwargs – Optional arguments that request takes.
Return type:

requests.Response

get_adapter(url)[source]

Returns the appropriate connection adapter for the given URL.

Return type: requests.adapters.BaseAdapter
get_redirect_target(resp)

Receives a Response. Returns a redirect URI or None

head(url, **kwargs)[source]

Sends a HEAD request. Returns Response object.

Parameters:
  • url – URL for the new Request object.
  • **kwargs – Optional arguments that request takes.
Return type:

requests.Response

A case-insensitive dictionary of headers to be sent on each
Request sent from this
Session.

hooks = None

Event-handling hooks.

max_redirects = None

Maximum number of redirects allowed. If the request exceeds this
limit, a TooManyRedirects exception is raised.
This defaults to requests.models.DEFAULT_REDIRECT_LIMIT, which is
30.

merge_environment_settings(url, proxies, stream, verify, cert)[source]

Check the environment and merge it with some settings.

Return type: dict
mount(prefix, adapter)[source]

Registers a connection adapter to a prefix.

Adapters are sorted in descending order by prefix length.

options(url, **kwargs)[source]

Sends a OPTIONS request. Returns Response object.

Parameters:
  • url – URL for the new Request object.
  • **kwargs – Optional arguments that request takes.
Return type:

requests.Response

params = None

Dictionary of querystring data to attach to each
Request. The dictionary values may be lists for
representing multivalued query parameters.

patch(url, data=None, **kwargs)[source]

Sends a PATCH request. Returns Response object.

Parameters:
  • url – URL for the new Request object.
  • data – (optional) Dictionary, list of tuples, bytes, or file-like
    object to send in the body of the Request.
  • **kwargs – Optional arguments that request takes.
Return type:

requests.Response

post(url, data=None, json=None, **kwargs)[source]

Sends a POST request. Returns Response object.

Parameters:
  • url – URL for the new Request object.
  • data – (optional) Dictionary, list of tuples, bytes, or file-like
    object to send in the body of the Request.
  • json – (optional) json to send in the body of the Request.
  • **kwargs – Optional arguments that request takes.
Return type:

requests.Response

prepare_request(request)[source]

Constructs a PreparedRequest for
transmission and returns it. The PreparedRequest has settings
merged from the Request instance and those of the
Session.

Parameters: requestRequest instance to prepare with this
session’s settings.
Return type: requests.PreparedRequest
proxies = None

Dictionary mapping protocol or protocol and host to the URL of the proxy
(e.g. {‘http’: ‘foo.bar:3128’, ‘http://host.name’: ‘foo.bar:4012’}) to
be used on each Request.

put(url, data=None, **kwargs)[source]

Sends a PUT request. Returns Response object.

Parameters:
  • url – URL for the new Request object.
  • data – (optional) Dictionary, list of tuples, bytes, or file-like
    object to send in the body of the Request.
  • **kwargs – Optional arguments that request takes.
Return type:

requests.Response

rebuild_auth(prepared_request, response)

When being redirected we may want to strip authentication from the
request to avoid leaking credentials. This method intelligently removes
and reapplies authentication where possible to avoid credential loss.

rebuild_method(prepared_request, response)

When being redirected we may want to change the method of the request
based on certain specs or browser behavior.

rebuild_proxies(prepared_request, proxies)

This method re-evaluates the proxy configuration by considering the
environment variables. If we are redirected to a URL covered by
NO_PROXY, we strip the proxy configuration. Otherwise, we set missing
proxy keys for this URL (in case they were stripped by a previous
redirect).

This method also replaces the Proxy-Authorization header where
necessary.

Return type: dict
request(method, url, params=None, data=None, headers=None, cookies=None, files=None, auth=None, timeout=None, allow_redirects=True, proxies=None, hooks=None, stream=None, verify=None, cert=None, json=None)[source]

Constructs a Request, prepares it and sends it.
Returns Response object.

Parameters:
  • method – method for the new Request object.
  • url – URL for the new Request object.
  • params – (optional) Dictionary or bytes to be sent in the query
    string for the Request.
  • data – (optional) Dictionary, list of tuples, bytes, or file-like
    object to send in the body of the Request.
  • json – (optional) json to send in the body of the
    Request.
  • headers – (optional) Dictionary of HTTP Headers to send with the
    Request.
  • cookies – (optional) Dict or CookieJar object to send with the
    Request.
  • files – (optional) Dictionary of 'filename': file-like-objects
    for multipart encoding upload.
  • auth – (optional) Auth tuple or callable to enable
    Basic/Digest/Custom HTTP Auth.
  • timeout (float or tuple) – (optional) How long to wait for the server to send
    data before giving up, as a float, or a (connect timeout,
    read timeout)
    tuple.
  • allow_redirects (bool) – (optional) Set to True by default.
  • proxies – (optional) Dictionary mapping protocol or protocol and
    hostname to the URL of the proxy.
  • stream – (optional) whether to immediately download the response
    content. Defaults to False.
  • verify – (optional) Either a boolean, in which case it controls whether we verify
    the server’s TLS certificate, or a string, in which case it must be a path
    to a CA bundle to use. Defaults to True.
  • cert – (optional) if String, path to ssl client cert file (.pem).
    If Tuple, (‘cert’, ‘key’) pair.
Return type:

requests.Response

resolve_redirects(resp, req, stream=False, timeout=None, verify=True, cert=None, proxies=None, yield_requests=False, **adapter_kwargs)

Receives a Response. Returns a generator of Responses or Requests.

send(request, **kwargs)[source]

Send a given PreparedRequest.

Return type: requests.Response
should_strip_auth(old_url, new_url)

Decide whether Authorization header should be removed when redirecting

stream = None

Stream response content default.

trust_env = None

Trust environment settings for proxy configuration, default
authentication and similar.

verify = None

SSL Verification default.

Lower-Level Classes¶

class requests.Request(method=None, url=None, headers=None, files=None, data=None, params=None, auth=None, cookies=None, hooks=None, json=None)[source]

A user-created Request object.

Used to prepare a PreparedRequest, which is sent to the server.

Parameters:
  • method – HTTP method to use.
  • url – URL to send.
  • headers – dictionary of headers to send.
  • files – dictionary of {filename: fileobject} files to multipart upload.
  • data – the body to attach to the request. If a dictionary or
    list of tuples [(key, value)] is provided, form-encoding will
    take place.
  • json – json for the body to attach to the request (if files or data is not specified).
  • params – URL parameters to append to the URL. If a dictionary or
    list of tuples [(key, value)] is provided, form-encoding will
    take place.
  • auth – Auth handler or (user, pass) tuple.
  • cookies – dictionary or CookieJar of cookies to attach to this request.
  • hooks – dictionary of callback hooks, for internal usage.

Usage:

>>> import requests
>>> req = requests.Request('GET', 'https://httpbin.org/get')
>>> req.prepare()
<PreparedRequest [GET]>
deregister_hook(event, hook)

Deregister a previously registered hook.
Returns True if the hook existed, False if not.

prepare()[source]

Constructs a PreparedRequest for transmission and returns it.

register_hook(event, hook)

Properly register a hook.

class requests.Response[source]

The Response object, which contains a
server’s response to an HTTP request.

apparent_encoding

The apparent encoding, provided by the chardet library.

close()[source]

Releases the connection back to the pool. Once this method has been
called the underlying raw object must not be accessed again.

Note: Should not normally need to be called explicitly.

content

Content of the response, in bytes.

cookies = None

A CookieJar of Cookies the server sent back.

elapsed = None

The amount of time elapsed between sending the request
and the arrival of the response (as a timedelta).
This property specifically measures the time taken between sending
the first byte of the request and finishing parsing the headers. It
is therefore unaffected by consuming the response content or the
value of the stream keyword argument.

encoding = None

Encoding to decode with when accessing r.text.

Case-insensitive Dictionary of Response Headers.
For example, headers['content-encoding'] will return the
value of a 'Content-Encoding' response header.

history = None

A list of Response objects from
the history of the Request. Any redirect responses will end
up here. The list is sorted from the oldest to the most recent request.

is_permanent_redirect

True if this Response one of the permanent versions of redirect.

is_redirect

True if this Response is a well-formed HTTP redirect that could have
been processed automatically (by Session.resolve_redirects).

iter_content(chunk_size=1, decode_unicode=False)[source]

Iterates over the response data. When stream=True is set on the
request, this avoids reading the content at once into memory for
large responses. The chunk size is the number of bytes it should
read into memory. This is not necessarily the length of each item
returned as decoding can take place.

chunk_size must be of type int or None. A value of None will
function differently depending on the value of stream.
stream=True will read data as it arrives in whatever size the
chunks are received. If stream=False, data is returned as
a single chunk.

If decode_unicode is True, content will be decoded using the best
available encoding based on the response.

iter_lines(chunk_size=512, decode_unicode=False, delimiter=None)[source]

Iterates over the response data, one line at a time. When
stream=True is set on the request, this avoids reading the
content at once into memory for large responses.

Note

This method is not reentrant safe.

json(**kwargs)[source]

Returns the json-encoded content of a response, if any.

Parameters: **kwargs – Optional arguments that json.loads takes.
Raises: ValueError – If the response body does not contain valid json.
links

Returns the parsed header links of the response, if any.

next

Returns a PreparedRequest for the next request in a redirect chain, if there is one.

ok

Returns True if status_code is less than 400, False if not.

This attribute checks if the status code of the response is between
400 and 600 to see if there was a client error or a server error. If
the status code is between 200 and 400, this will return True. This
is not a check to see if the response code is 200 OK.

raise_for_status()[source]

Raises stored HTTPError, if one occurred.

reason = None

Textual reason of responded HTTP Status, e.g. “Not Found” or “OK”.

request = None

The PreparedRequest object to which this
is a response.

status_code = None

Integer Code of responded HTTP Status, e.g. 404 or 200.

text

Content of the response, in unicode.

If Response.encoding is None, encoding will be guessed using
chardet.

The encoding of the response content is determined based solely on HTTP
headers, following RFC 2616 to the letter. If you can take advantage of
non-HTTP knowledge to make a better guess at the encoding, you should
set r.encoding appropriately before accessing this property.

url = None

Final URL location of Response.

Lower-Lower-Level Classes¶

class requests.PreparedRequest[source]

The fully mutable PreparedRequest object,
containing the exact bytes that will be sent to the server.

Generated from either a Request object or manually.

Usage:

>>> import requests
>>> req = requests.Request('GET', 'https://httpbin.org/get')
>>> r = req.prepare()
<PreparedRequest [GET]>

>>> s = requests.Session()
>>> s.send(r)
<Response [200]>
body = None

request body to send to the server.

deregister_hook(event, hook)

Deregister a previously registered hook.
Returns True if the hook existed, False if not.

dictionary of HTTP headers.

hooks = None

dictionary of callback hooks, for internal usage.

method = None

HTTP verb to send to the server.

path_url

Build the path URL to use.

prepare(method=None, url=None, headers=None, files=None, data=None, params=None, auth=None, cookies=None, hooks=None, json=None)[source]

Prepares the entire request with the given parameters.

prepare_auth(auth, url=»)[source]

Prepares the given HTTP auth data.

prepare_body(data, files, json=None)[source]

Prepares the given HTTP body data.

prepare_content_length(body)[source]

Prepare Content-Length header based on request method and body

prepare_cookies(cookies)[source]

Prepares the given HTTP cookie data.

This function eventually generates a Cookie header from the
given cookies using cookielib. Due to cookielib’s design, the header
will not be regenerated if it already exists, meaning this function
can only be called once for the life of the
PreparedRequest object. Any subsequent calls
to prepare_cookies will have no actual effect, unless the “Cookie”
header is removed beforehand.

Prepares the given HTTP headers.

prepare_hooks(hooks)[source]

Prepares the given hooks.

prepare_method(method)[source]

Prepares the given HTTP method.

prepare_url(url, params)[source]

Prepares the given HTTP URL.

register_hook(event, hook)

Properly register a hook.

url = None

HTTP URL to send the request to.

class requests.adapters.BaseAdapter[source]

The Base Transport Adapter

close()[source]

Cleans up adapter specific items.

send(request, stream=False, timeout=None, verify=True, cert=None, proxies=None)[source]

Sends PreparedRequest object. Returns Response object.

Parameters:
  • request – The PreparedRequest being sent.
  • stream – (optional) Whether to stream the request content.
  • timeout (float or tuple) – (optional) How long to wait for the server to send
    data before giving up, as a float, or a (connect timeout,
    read timeout)
    tuple.
  • verify – (optional) Either a boolean, in which case it controls whether we verify
    the server’s TLS certificate, or a string, in which case it must be a path
    to a CA bundle to use
  • cert – (optional) Any user-provided SSL certificate to be trusted.
  • proxies – (optional) The proxies dictionary to apply to the request.
class requests.adapters.HTTPAdapter(pool_connections=10, pool_maxsize=10, max_retries=0, pool_block=False)[source]

The built-in HTTP Adapter for urllib3.

Provides a general-case interface for Requests sessions to contact HTTP and
HTTPS urls by implementing the Transport Adapter interface. This class will
usually be created by the Session class under the
covers.

Parameters:
  • pool_connections – The number of urllib3 connection pools to cache.
  • pool_maxsize – The maximum number of connections to save in the pool.
  • max_retries – The maximum number of retries each connection
    should attempt. Note, this applies only to failed DNS lookups, socket
    connections and connection timeouts, never to requests where data has
    made it to the server. By default, Requests does not retry failed
    connections. If you need granular control over the conditions under
    which we retry a request, import urllib3’s Retry class and pass
    that instead.
  • pool_block – Whether the connection pool should block for connections.

Usage:

>>> import requests
>>> s = requests.Session()
>>> a = requests.adapters.HTTPAdapter(max_retries=3)
>>> s.mount('http://', a)

Add any headers needed by the connection. As of v2.0 this does
nothing by default, but is left for overriding by users that subclass
the HTTPAdapter.

This should not be called from user code, and is only exposed for use
when subclassing the
HTTPAdapter.

Parameters:
  • request – The PreparedRequest to add headers to.
  • kwargs – The keyword arguments from the call to send().
build_response(req, resp)[source]

Builds a Response object from a urllib3
response. This should not be called from user code, and is only exposed
for use when subclassing the
HTTPAdapter

Parameters:
  • req – The PreparedRequest used to generate the response.
  • resp – The urllib3 response object.
Return type:

requests.Response

cert_verify(conn, url, verify, cert)[source]

Verify a SSL certificate. This method should not be called from user
code, and is only exposed for use when subclassing the
HTTPAdapter.

Parameters:
  • conn – The urllib3 connection object associated with the cert.
  • url – The requested URL.
  • verify – Either a boolean, in which case it controls whether we verify
    the server’s TLS certificate, or a string, in which case it must be a path
    to a CA bundle to use
  • cert – The SSL certificate to verify.
close()[source]

Disposes of any internal state.

Currently, this closes the PoolManager and any active ProxyManager,
which closes any pooled connections.

get_connection(url, proxies=None)[source]

Returns a urllib3 connection for the given URL. This should not be
called from user code, and is only exposed for use when subclassing the
HTTPAdapter.

Parameters:
  • url – The URL to connect to.
  • proxies – (optional) A Requests-style dictionary of proxies used on this request.
Return type:

urllib3.ConnectionPool

init_poolmanager(connections, maxsize, block=False, **pool_kwargs)[source]

Initializes a urllib3 PoolManager.

This method should not be called from user code, and is only
exposed for use when subclassing the
HTTPAdapter.

Parameters:
  • connections – The number of urllib3 connection pools to cache.
  • maxsize – The maximum number of connections to save in the pool.
  • block – Block when no free connections are available.
  • pool_kwargs – Extra keyword arguments used to initialize the Pool Manager.

Returns a dictionary of the headers to add to any request sent
through a proxy. This works with urllib3 magic to ensure that they are
correctly sent to the proxy, rather than in a tunnelled request if
CONNECT is being used.

This should not be called from user code, and is only exposed for use
when subclassing the
HTTPAdapter.

Parameters: proxy – The url of the proxy being used for this request.
Return type: dict
proxy_manager_for(proxy, **proxy_kwargs)[source]

Return urllib3 ProxyManager for the given proxy.

This method should not be called from user code, and is only
exposed for use when subclassing the
HTTPAdapter.

Parameters:
  • proxy – The proxy to return a urllib3 ProxyManager for.
  • proxy_kwargs – Extra keyword arguments used to configure the Proxy Manager.
Returns:

ProxyManager

Return type:

urllib3.ProxyManager

request_url(request, proxies)[source]

Obtain the url to use when making the final request.

If the message is being sent through a HTTP proxy, the full URL has to
be used. Otherwise, we should only use the path portion of the URL.

This should not be called from user code, and is only exposed for use
when subclassing the
HTTPAdapter.

Parameters:
  • request – The PreparedRequest being sent.
  • proxies – A dictionary of schemes or schemes and hosts to proxy URLs.
Return type:

str

send(request, stream=False, timeout=None, verify=True, cert=None, proxies=None)[source]

Sends PreparedRequest object. Returns Response object.

Parameters:
  • request – The PreparedRequest being sent.
  • stream – (optional) Whether to stream the request content.
  • timeout (float or tuple or urllib3 Timeout object) – (optional) How long to wait for the server to send
    data before giving up, as a float, or a (connect timeout,
    read timeout)
    tuple.
  • verify – (optional) Either a boolean, in which case it controls whether
    we verify the server’s TLS certificate, or a string, in which case it
    must be a path to a CA bundle to use
  • cert – (optional) Any user-provided SSL certificate to be trusted.
  • proxies – (optional) The proxies dictionary to apply to the request.
Return type:

requests.Response

Authentication¶

class requests.auth.AuthBase[source]

Base class that all auth implementations derive from

class requests.auth.HTTPBasicAuth(username, password)[source]

Attaches HTTP Basic Authentication to the given Request object.

class requests.auth.HTTPDigestAuth(username, password)[source]

Attaches HTTP Digest Authentication to the given Request object.

Encodings¶

requests.utils.get_encodings_from_content(content)[source]

Returns encodings from given content string.

Parameters: content – bytestring to extract encodings from.

Returns encodings from given HTTP Header Dict.

Parameters: headers – dictionary to extract encoding from.
Return type: str
requests.utils.get_unicode_from_response(r)[source]

Returns the requested content back in unicode.

Parameters: r – Response object to get unicode content from.

Tried:

  1. charset from content-type
  2. fall back and replace all unicode characters
Return type: str

Cookies¶

requests.utils.dict_from_cookiejar(cj)[source]

Returns a key/value dictionary from a CookieJar.

Parameters: cj – CookieJar object to extract cookies from.
Return type: dict
requests.utils.add_dict_to_cookiejar(cj, cookie_dict)[source]

Returns a CookieJar from a key/value dictionary.

Parameters:
  • cj – CookieJar to insert cookies into.
  • cookie_dict – Dict of key/values to insert into CookieJar.
Return type:

CookieJar

requests.cookies.cookiejar_from_dict(cookie_dict, cookiejar=None, overwrite=True)[source]

Returns a CookieJar from a key/value dictionary.

Parameters:
  • cookie_dict – Dict of key/values to insert into CookieJar.
  • cookiejar – (optional) A cookiejar to add the cookies to.
  • overwrite – (optional) If False, will not replace cookies
    already in the jar with new ones.
Return type:

CookieJar

class requests.cookies.RequestsCookieJar(policy=None)[source]

Compatibility class; is a cookielib.CookieJar, but exposes a dict
interface.

This is the CookieJar we create by default for requests and sessions that
don’t specify one, since some clients may expect response.cookies and
session.cookies to support dict operations.

Requests does not use the dict interface internally; it’s just for
compatibility with external client code. All requests code should work
out of the box with externally provided instances of CookieJar, e.g.
LWPCookieJar and FileCookieJar.

Unlike a regular CookieJar, this class is pickleable.

Warning

dictionary operations that are normally O(1) may be O(n).

Add correct Cookie: header to request (urllib.request.Request object).

The Cookie2 header is also added unless policy.hide_cookie2 is true.

clear(domain=None, path=None, name=None)

Clear some cookies.

Invoking this method without arguments will clear all cookies. If
given a single argument, only cookies belonging to that domain will be
removed. If given two arguments, cookies belonging to the specified
path within that domain are removed. If given three arguments, then
the cookie with the specified name, path and domain is removed.

Raises KeyError if no matching cookie exists.

clear_expired_cookies()

Discard all expired cookies.

You probably don’t need to call this method: expired cookies are never
sent back to the server (provided you’re using DefaultCookiePolicy),
this method is called by CookieJar itself every so often, and the
.save() method won’t save expired cookies anyway (unless you ask
otherwise by passing a true ignore_expires argument).

clear_session_cookies()

Discard all session cookies.

Note that the .save() method won’t save session cookies anyway, unless
you ask otherwise by passing a true ignore_discard argument.

copy()[source]

Return a copy of this RequestsCookieJar.

Extract cookies from response, where allowable given the request.

get(name, default=None, domain=None, path=None)[source]

Dict-like get() that also supports optional domain and path args in
order to resolve naming collisions from using one cookie jar over
multiple domains.

Warning

operation is O(n), not O(1).

get_dict(domain=None, path=None)[source]

Takes as an argument an optional domain and path and returns a plain
old Python dict of name-value pairs of cookies that meet the
requirements.

Return type: dict
get_policy()[source]

Return the CookiePolicy instance used.

items()[source]

Dict-like items() that returns a list of name-value tuples from the
jar. Allows client-code to call dict(RequestsCookieJar) and get a
vanilla python dict of key value pairs.

See also

keys() and values().

iteritems()[source]

Dict-like iteritems() that returns an iterator of name-value tuples
from the jar.

See also

iterkeys() and itervalues().

iterkeys()[source]

Dict-like iterkeys() that returns an iterator of names of cookies
from the jar.

See also

itervalues() and iteritems().

itervalues()[source]

Dict-like itervalues() that returns an iterator of values of cookies
from the jar.

See also

iterkeys() and iteritems().

keys()[source]

Dict-like keys() that returns a list of names of cookies from the
jar.

See also

values() and items().

list_domains()[source]

Utility method to list all the domains in the jar.

list_paths()[source]

Utility method to list all the paths in the jar.

make_cookies(response, request)

Return sequence of Cookie objects extracted from response object.

multiple_domains()[source]

Returns True if there are multiple domains in the jar.
Returns False otherwise.

Return type: bool
pop(k[, d]) → v, remove specified key and return the corresponding value.¶

If key is not found, d is returned if given, otherwise KeyError is raised.

popitem() → (k, v), remove and return some (key, value) pair¶

as a 2-tuple; but raise KeyError if D is empty.

set(name, value, **kwargs)[source]

Dict-like set() that also supports optional domain and path args in
order to resolve naming collisions from using one cookie jar over
multiple domains.

set_cookie(cookie, *args, **kwargs)[source]

Set a cookie, without checking whether or not it should be set.

set_cookie_if_ok(cookie, request)

Set a cookie if policy says it’s OK to do so.

setdefault(k[, d]) → D.get(k,d), also set D[k]=d if k not in D¶
update(other)[source]

Updates this jar with cookies from another CookieJar or dict-like

values()[source]

Dict-like values() that returns a list of values of cookies from the
jar.

See also

keys() and items().

class requests.cookies.CookieConflictError[source]

There are two cookies that meet the criteria specified in the cookie jar.
Use .get and .set and include domain and path args in order to be more specific.

with_traceback()

Exception.with_traceback(tb) –
set self.__traceback__ to tb and return self.

Status Code Lookup¶

requests.codes

The codes object defines a mapping from common names for HTTP statuses
to their numerical codes, accessible either as attributes or as dictionary
items.

>>> requests.codes['temporary_redirect']
307
>>> requests.codes.teapot
418
>>> requests.codes['o/']
200

Some codes have multiple names, and both upper- and lower-case versions of
the names are allowed. For example, codes.ok, codes.OK, and
codes.okay all correspond to the HTTP status code 200.

  • 100: continue
  • 101: switching_protocols
  • 102: processing
  • 103: checkpoint
  • 122: uri_too_long, request_uri_too_long
  • 200: ok, okay, all_ok, all_okay, all_good, o/,
  • 201: created
  • 202: accepted
  • 203: non_authoritative_info, non_authoritative_information
  • 204: no_content
  • 205: reset_content, reset
  • 206: partial_content, partial
  • 207: multi_status, multiple_status, multi_stati, multiple_stati
  • 208: already_reported
  • 226: im_used
  • 300: multiple_choices
  • 301: moved_permanently, moved, o-
  • 302: found
  • 303: see_other, other
  • 304: not_modified
  • 305: use_proxy
  • 306: switch_proxy
  • 307: temporary_redirect, temporary_moved, temporary
  • 308: permanent_redirect, resume_incomplete, resume
  • 400: bad_request, bad
  • 401: unauthorized
  • 402: payment_required, payment
  • 403: forbidden
  • 404: not_found, -o-
  • 405: method_not_allowed, not_allowed
  • 406: not_acceptable
  • 407: proxy_authentication_required, proxy_auth, proxy_authentication
  • 408: request_timeout, timeout
  • 409: conflict
  • 410: gone
  • 411: length_required
  • 412: precondition_failed, precondition
  • 413: request_entity_too_large
  • 414: request_uri_too_large
  • 415: unsupported_media_type, unsupported_media, media_type
  • 416: requested_range_not_satisfiable, requested_range, range_not_satisfiable
  • 417: expectation_failed
  • 418: im_a_teapot, teapot, i_am_a_teapot
  • 421: misdirected_request
  • 422: unprocessable_entity, unprocessable
  • 423: locked
  • 424: failed_dependency, dependency
  • 425: unordered_collection, unordered
  • 426: upgrade_required, upgrade
  • 428: precondition_required, precondition
  • 429: too_many_requests, too_many
  • 431: header_fields_too_large, fields_too_large
  • 444: no_response, none
  • 449: retry_with, retry
  • 450: blocked_by_windows_parental_controls, parental_controls
  • 451: unavailable_for_legal_reasons, legal_reasons
  • 499: client_closed_request
  • 500: internal_server_error, server_error, /o,
  • 501: not_implemented
  • 502: bad_gateway
  • 503: service_unavailable, unavailable
  • 504: gateway_timeout
  • 505: http_version_not_supported, http_version
  • 506: variant_also_negotiates
  • 507: insufficient_storage
  • 509: bandwidth_limit_exceeded, bandwidth
  • 510: not_extended
  • 511: network_authentication_required, network_auth, network_authentication

Migrating to 1.x¶

This section details the main differences between 0.x and 1.x and is meant
to ease the pain of upgrading.

API Changes¶

  • Response.json is now a callable and not a property of a response.

    import requests
    r = requests.get('https://github.com/timeline.json')
    r.json()   # This *call* raises an exception if JSON decoding fails
    
  • The Session API has changed. Sessions objects no longer take parameters.
    Session is also now capitalized, but it can still be
    instantiated with a lowercase session for backwards compatibility.

    s = requests.Session()    # formerly, session took parameters
    s.auth = auth
    s.headers.update(headers)
    r = s.get('https://httpbin.org/headers')
    
  • All request hooks have been removed except ‘response’.

  • Authentication helpers have been broken out into separate modules. See
    requests-oauthlib and requests-kerberos.

  • The parameter for streaming requests was changed from prefetch to
    stream and the logic was inverted. In addition, stream is now
    required for raw response reading.

    # in 0.x, passing prefetch=False would accomplish the same thing
    r = requests.get('https://github.com/timeline.json', stream=True)
    for chunk in r.iter_content(8192):
        ...
    
  • The config parameter to the requests method has been removed. Some of
    these options are now configured on a Session such as keep-alive and
    maximum number of redirects. The verbosity option should be handled by
    configuring logging.

    import requests
    import logging
    
    # Enabling debugging at http.client level (requests->urllib3->http.client)
    # you will see the REQUEST, including HEADERS and DATA, and RESPONSE with HEADERS but without DATA.
    # the only thing missing will be the response.body which is not logged.
    try: # for Python 3
        from http.client import HTTPConnection
    except ImportError:
        from httplib import HTTPConnection
    HTTPConnection.debuglevel = 1
    
    logging.basicConfig() # you need to initialize logging, otherwise you will not see anything from requests
    logging.getLogger().setLevel(logging.DEBUG)
    requests_log = logging.getLogger("urllib3")
    requests_log.setLevel(logging.DEBUG)
    requests_log.propagate = True
    
    requests.get('https://httpbin.org/headers')
    

Licensing¶

One key difference that has nothing to do with the API is a change in the
license from the ISC license to the Apache 2.0 license. The Apache 2.0
license ensures that contributions to Requests are also covered by the Apache
2.0 license.

Migrating to 2.x¶

Compared with the 1.0 release, there were relatively few backwards
incompatible changes, but there are still a few issues to be aware of with
this major release.

For more details on the changes in this release including new APIs, links
to the relevant GitHub issues and some of the bug fixes, read Cory’s blog
on the subject.

API Changes¶

  • There were a couple changes to how Requests handles exceptions.
    RequestException is now a subclass of IOError rather than
    RuntimeError as that more accurately categorizes the type of error.
    In addition, an invalid URL escape sequence now raises a subclass of
    RequestException rather than a ValueError.

    requests.get('http://%zz/')   # raises requests.exceptions.InvalidURL
    

    Lastly, httplib.IncompleteRead exceptions caused by incorrect chunked
    encoding will now raise a Requests ChunkedEncodingError instead.

  • The proxy API has changed slightly. The scheme for a proxy URL is now
    required.

    proxies = {
      "http": "10.10.1.10:3128",    # use http://10.10.1.10:3128 instead
    }
    
    # In requests 1.x, this was legal, in requests 2.x,
    #  this raises requests.exceptions.MissingScheme
    requests.get("http://example.org", proxies=proxies)
    

Behavioural Changes¶

  • Keys in the headers dictionary are now native strings on all Python
    versions, i.e. bytestrings on Python 2 and unicode on Python 3. If the
    keys are not native strings (unicode on Python 2 or bytestrings on Python 3)
    they will be converted to the native string type assuming UTF-8 encoding.
  • Values in the headers dictionary should always be strings. This has
    been the project’s position since before 1.0 but a recent change
    (since version 2.11.0) enforces this more strictly. It’s advised to avoid
    passing header values as unicode when possible.

Python request module is a simple and elegant Python HTTP library. It provides methods for accessing Web resources via HTTP. In the following article, we will use the HTTP GET method in the Request module. This method requests data from the server and the Exception handling comes in handy when the response is not successful. Here, we will go through such situations. We will use Python’s try and except functionality to explore the exceptions that arise from the Requests module.

  • url: Returns the URL of the response
  • raise_for_status(): If an error occur, this method returns a HTTPError object
  • request: Returns the request object that requested this response
  • status_code: Returns a number that indicates the status (200 is OK, 404 is Not Found)
     

Successful Connection Request

The first thing to know is that the response code is 200 if the request is successful.

Python3

Output:

200

Exception Handling for HTTP Errors

Here, we tried the following URL sequence and then passed this variable to the Python requests module using raised_for_status(). If the try part is successful, we will get the response code 200, if the page that we requested doesn’t exist. This is an HTTP error, which was handled by the Request module’s exception HTTPError and you probably got the error 404.

Python3

import requests

try:

    r = requests.get(url, timeout=1)

    r.raise_for_status()

except requests.exceptions.HTTPError as errh:

    print("HTTP Error")

    print(errh.args[0])

print(r)

Output:

HTTP Error
404 Client Error: Not Found for url: https://www.amazon.com/nothing_here
<Response [404]>

General Exception Handling

You could also use a general exception from the Request module. That is requests.exceptions.RequestException.

Python3

try:

    r = requests.get(url, timeout=1)

    r.raise_for_status()

except requests.exceptions.RequestException as errex:

    print("Exception request")

Output:

Exception request 

Now, you may have noticed that there is an argument ‘timeout’ passed into the Request module. We could prescribe a time limit for the requested connection to respond. If this has not happened, we could catch that using the exception requests.exceptions.ReadTimeout. To demonstrate this let us find a website that responds successfully.

Python3

import requests

try:

    r = requests.get(url, timeout=1)

    r.raise_for_status()

except requests.exceptions.ReadTimeout as errrt:

    print("Time out")

print(r)

Output:

<Response [200]>

If we change timeout = 0.01, the same code would return, because the request could not possibly be that fast.

Time out
<Response [200]>

Exception Handling for Missing Schema

Another common error is that we might not specify HTTPS or HTTP in the URL. For example, We cause use requests.exceptions.MissingSchema to catch this exception.

Python3

url = "www.google.com"

try:

    r = requests.get(url, timeout=1)

    r.raise_for_status()

except requests.exceptions.MissingSchema as errmiss:

    print("Missing schema: include http or https")

except requests.exceptions.ReadTimeout as errrt:

    print("Time out")

Output:

Missing scheme: include http or https

Exception Handling for Connection Error

Let us say that there is a site that doesn’t exist. Here, the error will occur even when you can’t make a connection because of the lack of an internet connection

Python3

try:

  r = requests.get(url, timeout = 1, verify = True)

  r.raise_for_status()

except requests.exceptions.HTTPError as errh:

  print("HTTP Error")

  print(errh.args[0])

except requests.exceptions.ReadTimeout as errrt:

  print("Time out")

except requests.exceptions.ConnectionError as conerr:

  print("Connection error")

Output:

Connection error

Putting Everything Together

Here, We put together everything we tried so far the idea is that the exceptions are handled according to the specificity. 

For example, url =  “https://www.gle.com”,  When this code is run for this URL will produce an Exception request. Whereas, In the absence of connection requests.exceptions.ConnectionError will print the Connection Error, and when the connection is not made the general exception is handled by requests.exceptions.RequestException.

Python3

try:

    r = requests.get(url, timeout=1, verify=True)

    r.raise_for_status()

except requests.exceptions.HTTPError as errh:

    print("HTTP Error")

    print(errh.args[0])

except requests.exceptions.ReadTimeout as errrt:

    print("Time out")

except requests.exceptions.ConnectionError as conerr:

    print("Connection error")

except requests.exceptions.RequestException as errex:

    print("Exception request")

Output:

Note: The output may change according to requests.

 Time out

Библиотека requests является стандартным инструментом для составления HTTP-запросов в Python. Простой и аккуратный API значительно облегчает трудоемкий процесс создания запросов. Таким образом, можно сосредоточиться на взаимодействии со службами и использовании данных в приложении.

Содержание статьи

  • Python установка библиотеки requests
  • Python библиотека Requests метод GET
  • Объект Response получение ответа на запрос в Python
  • HTTP коды состояний
  • Получить содержимое страницы в Requests
  • HTTP заголовки в Requests
  • Python Requests параметры запроса
  • Настройка HTTP заголовка запроса (headers)
  • Примеры HTTP методов в Requests
  • Python Requests тело сообщения
  • Python Requests анализ запроса
  • Python Requests аутентификация HTTP AUTH
  • Python Requests проверка SSL сертификата
  • Python Requests производительность приложений
  • Объект Session в Requests
  • HTTPAdapter — Максимальное количество повторов запроса в Requests

В данной статье представлены наиболее полезные особенности requests. Показано, как изменить и приспособить requests к различным ситуациям, с которыми программисты сталкиваются чаще всего. Здесь также даются советы по эффективному использованию requests и предотвращению влияния сторонних служб, которые могут сильно замедлить работу используемого приложения. Мы использовали библиотек requests в уроке по парсингу html через библиотеку BeautifulSoup.

Ключевые аспекты инструкции:

  • Создание запросов при помощи самых популярных HTTP методов;
  • Редактирование заголовков запросов и данных при помощи строки запроса и содержимого сообщения;
  • Анализ данных запросов и откликов;
  • Создание авторизированных запросов;
  • Настройка запросов для предотвращения сбоев и замедления работы приложения.

В статье собран оптимальный набор информации, необходимый для понимания данных примеров и особенностей их использования. Информация представлена в доступной в форме. Тем не менее, стоит иметь в виду, что для оптимального разбора инструкции потребуются хотя бы базовые знания HTTP.

Далее будут показаны наиболее эффективные методы использования requests в разрабатываемом приложении.

Python установка библиотеки requests

Для начала работы потребуется установить библиотеку requests. Для этого используется следующая команда.

Есть вопросы по Python?

На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!

Telegram Чат & Канал

Вступите в наш дружный чат по Python и начните общение с единомышленниками! Станьте частью большого сообщества!

Паблик VK

Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!

Тем, кто для работы с пакетами Python, использует виртуальную среду Pipenv, необходимо использовать немного другую команду.

$ pipenv install requests

Сразу после установки requests можно полноценно использовать в приложении. Импорт requests производится следующим образом.

Таким образом, все подготовительные этапы для последующего использования requests завершены. Начинать изучение requests лучше всего с того, как сделать запрос GET.

Python библиотека Requests метод GET

Такие HTTP методы, как GET и POST, определяют, какие действия будут выполнены при создании HTTP запроса. Помимо GET и POST для этой задачи могут быть использованы некоторые другие методы. Далее они также будут описаны в руководстве.

GET является одним из самых популярных HTTP методов. Метод GET указывает на то, что происходит попытка извлечь данные из определенного ресурса. Для того, чтобы выполнить запрос GET, используется requests.get().

Для проверки работы команды будет выполнен запрос GET в отношении Root REST API на GitHub. Для указанного ниже URL вызывается метод get().

requests.get(‘https://api.github.com’)

<Response [200]>

Если никакие python ошибки не возникло, вас можно поздравить – первый запрос успешно выполнен. Далее будет рассмотрен ответ на данный запрос, который можно получить при помощи объекта Response.

Объект Response получение ответа на запрос в Python

Response представляет собой довольно мощный объект для анализа результатов запроса. В качестве примера будет использован предыдущий запрос, только на этот раз результат будет представлен в виде переменной. Таким образом, получится лучше изучить его атрибуты и особенности использования.

response = requests.get(‘https://api.github.com’)

В данном примере при помощи get() захватывается определенное значение, что является частью объекта Response, и помещается в переменную под названием response. Теперь можно использовать переменную response для того, чтобы изучить данные, которые были получены в результате запроса GET.

HTTP коды состояний

Самыми первыми данными, которые будут получены через Response, будут коды состояния. Коды состояния сообщают о статусе запроса.

Например, статус 200 OK значит, что запрос успешно выполнен. А вот статус 404 NOT FOUND говорит о том, что запрашиваемый ресурс не был найден. Существует множество других статусных кодов, которые могут сообщить важную информацию, связанную с запросом.

Используя .status_code, можно увидеть код состояния, который возвращается с сервера.

>>> response.status_code

200

.status_code вернул значение 200. Это значит, что запрос был выполнен успешно, а сервер ответил, отобразив запрашиваемую информацию.

В некоторых случаях необходимо использовать полученную информацию для написания программного кода.

if response.status_code == 200:

    print(‘Success!’)

elif response.status_code == 404:

    print(‘Not Found.’)

В таком случае, если с сервера будет получен код состояния 200, тогда программа выведет значение Success!. Однако, если от сервера поступит код 404, тогда программа выведет значение Not Found.
requests может значительно упростить весь процесс. Если использовать Response в условных конструкциях, то при получении кода состояния в промежутке от 200 до 400, будет выведено значение True. В противном случае отобразится значение False.

Последний пример можно упростить при помощи использования оператора if.

if response:

    print(‘Success!’)

else:

    print(‘An error has occurred.’)

Стоит иметь в виду, что данный способ не проверяет, имеет ли статусный код точное значение 200. Причина заключается в том, что другие коды в промежутке от 200 до 400, например, 204 NO CONTENT и 304 NOT MODIFIED, также считаются успешными в случае, если они могут предоставить действительный ответ.

К примеру, код состояния 204 говорит о том, что ответ успешно получен, однако в полученном объекте нет содержимого. Можно сказать, что для оптимально эффективного использования способа необходимо убедиться, что начальный запрос был успешно выполнен. Требуется изучить код состояния и в случае необходимости произвести необходимые поправки, которые будут зависеть от значения полученного кода.

Допустим, если при использовании оператора if вы не хотите проверять код состояния, можно расширить диапазон исключений для неудачных результатов запроса. Это можно сделать при помощи использования .raise_for_status().

import requests

from requests.exceptions import HTTPError

for url in [‘https://api.github.com’, ‘https://api.github.com/invalid’]:

    try:

        response = requests.get(url)

        # если ответ успешен, исключения задействованы не будут

        response.raise_for_status()

    except HTTPError as http_err:

        print(f‘HTTP error occurred: {http_err}’)  # Python 3.6

    except Exception as err:

        print(f‘Other error occurred: {err}’)  # Python 3.6

    else:

        print(‘Success!’)

В случае вызова исключений через .raise_for_status() к некоторым кодам состояния применяется HTTPError. Когда код состояния показывает, что запрос успешно выполнен, программа продолжает работу без применения политики исключений.

На заметку. Для более продуктивной работы в Python 3.6 будет не лишним изучить f-строки. Не стоит пренебрегать ими, так как это отличный способ упростить форматирование строк.

Анализ способов использования кодов состояния, полученных с сервера, является неплохим стартом для изучения requests. Тем не менее, при создании запроса GET, значение кода состояния является не самой важной информацией, которую хочет получить программист. Обычно запрос производится для извлечения более содержательной информации. В дальнейшем будет показано, как добраться до актуальных данных, которые сервер высылает отправителю в ответ на запрос.

Зачастую ответ на запрос GET содержит весьма ценную информацию. Она находится в теле сообщения и называется пейлоад (payload). Используя атрибуты и методы библиотеки Response, можно получить пейлоад в различных форматах.

Для того, чтобы получить содержимое запроса в байтах, необходимо использовать .content.

>>> response = requests.get(‘https://api.github.com’)

>>> response.content

b‘{«current_user_url»:»https://api.github.com/user»,»current_user_authorizations_html_url»:»https://github.com/settings/connections/applications{/client_id}»,»authorizations_url»:»https://api.github.com/authorizations»,»code_search_url»:»https://api.github.com/search/code?q={query}{&page,per_page,sort,order}»,»commit_search_url»:»https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}»,»emails_url»:»https://api.github.com/user/emails»,»emojis_url»:»https://api.github.com/emojis»,»events_url»:»https://api.github.com/events»,»feeds_url»:»https://api.github.com/feeds»,»followers_url»:»https://api.github.com/user/followers»,»following_url»:»https://api.github.com/user/following{/target}»,»gists_url»:»https://api.github.com/gists{/gist_id}»,»hub_url»:»https://api.github.com/hub»,»issue_search_url»:»https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}»,»issues_url»:»https://api.github.com/issues»,»keys_url»:»https://api.github.com/user/keys»,»notifications_url»:»https://api.github.com/notifications»,»organization_repositories_url»:»https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}»,»organization_url»:»https://api.github.com/orgs/{org}»,»public_gists_url»:»https://api.github.com/gists/public»,»rate_limit_url»:»https://api.github.com/rate_limit»,»repository_url»:»https://api.github.com/repos/{owner}/{repo}»,»repository_search_url»:»https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}»,»current_user_repositories_url»:»https://api.github.com/user/repos{?type,page,per_page,sort}»,»starred_url»:»https://api.github.com/user/starred{/owner}{/repo}»,»starred_gists_url»:»https://api.github.com/gists/starred»,»team_url»:»https://api.github.com/teams»,»user_url»:»https://api.github.com/users/{user}»,»user_organizations_url»:»https://api.github.com/user/orgs»,»user_repositories_url»:»https://api.github.com/users/{user}/repos{?type,page,per_page,sort}»,»user_search_url»:»https://api.github.com/search/users?q={query}{&page,per_page,sort,order}»}’

Использование .content обеспечивает доступ к чистым байтам ответного пейлоада, то есть к любым данным в теле запроса. Однако, зачастую требуется конвертировать полученную информацию в строку в кодировке UTF-8. response делает это при помощи .text.

>>> response.text

‘{«current_user_url»:»https://api.github.com/user»,»current_user_authorizations_html_url»:»https://github.com/settings/connections/applications{/client_id}»,»authorizations_url»:»https://api.github.com/authorizations»,»code_search_url»:»https://api.github.com/search/code?q={query}{&page,per_page,sort,order}»,»commit_search_url»:»https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}»,»emails_url»:»https://api.github.com/user/emails»,»emojis_url»:»https://api.github.com/emojis»,»events_url»:»https://api.github.com/events»,»feeds_url»:»https://api.github.com/feeds»,»followers_url»:»https://api.github.com/user/followers»,»following_url»:»https://api.github.com/user/following{/target}»,»gists_url»:»https://api.github.com/gists{/gist_id}»,»hub_url»:»https://api.github.com/hub»,»issue_search_url»:»https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}»,»issues_url»:»https://api.github.com/issues»,»keys_url»:»https://api.github.com/user/keys»,»notifications_url»:»https://api.github.com/notifications»,»organization_repositories_url»:»https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}»,»organization_url»:»https://api.github.com/orgs/{org}»,»public_gists_url»:»https://api.github.com/gists/public»,»rate_limit_url»:»https://api.github.com/rate_limit»,»repository_url»:»https://api.github.com/repos/{owner}/{repo}»,»repository_search_url»:»https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}»,»current_user_repositories_url»:»https://api.github.com/user/repos{?type,page,per_page,sort}»,»starred_url»:»https://api.github.com/user/starred{/owner}{/repo}»,»starred_gists_url»:»https://api.github.com/gists/starred»,»team_url»:»https://api.github.com/teams»,»user_url»:»https://api.github.com/users/{user}»,»user_organizations_url»:»https://api.github.com/user/orgs»,»user_repositories_url»:»https://api.github.com/users/{user}/repos{?type,page,per_page,sort}»,»user_search_url»:»https://api.github.com/search/users?q={query}{&page,per_page,sort,order}»}’

Декодирование байтов в строку требует наличия определенной модели кодировки. По умолчанию requests попытается узнать текущую кодировку, ориентируясь по заголовкам HTTP. Указать необходимую кодировку можно при помощи добавления .encoding перед .text.

>>> response.encoding = ‘utf-8’ # Optional: requests infers this internally

>>> response.text

‘{«current_user_url»:»https://api.github.com/user»,»current_user_authorizations_html_url»:»https://github.com/settings/connections/applications{/client_id}»,»authorizations_url»:»https://api.github.com/authorizations»,»code_search_url»:»https://api.github.com/search/code?q={query}{&page,per_page,sort,order}»,»commit_search_url»:»https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}»,»emails_url»:»https://api.github.com/user/emails»,»emojis_url»:»https://api.github.com/emojis»,»events_url»:»https://api.github.com/events»,»feeds_url»:»https://api.github.com/feeds»,»followers_url»:»https://api.github.com/user/followers»,»following_url»:»https://api.github.com/user/following{/target}»,»gists_url»:»https://api.github.com/gists{/gist_id}»,»hub_url»:»https://api.github.com/hub»,»issue_search_url»:»https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}»,»issues_url»:»https://api.github.com/issues»,»keys_url»:»https://api.github.com/user/keys»,»notifications_url»:»https://api.github.com/notifications»,»organization_repositories_url»:»https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}»,»organization_url»:»https://api.github.com/orgs/{org}»,»public_gists_url»:»https://api.github.com/gists/public»,»rate_limit_url»:»https://api.github.com/rate_limit»,»repository_url»:»https://api.github.com/repos/{owner}/{repo}»,»repository_search_url»:»https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}»,»current_user_repositories_url»:»https://api.github.com/user/repos{?type,page,per_page,sort}»,»starred_url»:»https://api.github.com/user/starred{/owner}{/repo}»,»starred_gists_url»:»https://api.github.com/gists/starred»,»team_url»:»https://api.github.com/teams»,»user_url»:»https://api.github.com/users/{user}»,»user_organizations_url»:»https://api.github.com/user/orgs»,»user_repositories_url»:»https://api.github.com/users/{user}/repos{?type,page,per_page,sort}»,»user_search_url»:»https://api.github.com/search/users?q={query}{&page,per_page,sort,order}»}’

Если присмотреться к ответу, можно заметить, что его содержимое является сериализированным JSON контентом. Воспользовавшись словарем, можно взять полученные из .text строки str и провести с ними обратную сериализацию при помощи использования json.loads(). Есть и более простой способ, который требует применения .json().

>>> response.json()

{‘current_user_url’: ‘https://api.github.com/user’, ‘current_user_authorizations_html_url’: ‘https://github.com/settings/connections/applications{/client_id}’, ‘authorizations_url’: ‘https://api.github.com/authorizations’, ‘code_search_url’: ‘https://api.github.com/search/code?q={query}{&page,per_page,sort,order}’, ‘commit_search_url’: ‘https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}’, ’emails_url’: ‘https://api.github.com/user/emails’, ’emojis_url’: ‘https://api.github.com/emojis’, ‘events_url’: ‘https://api.github.com/events’, ‘feeds_url’: ‘https://api.github.com/feeds’, ‘followers_url’: ‘https://api.github.com/user/followers’, ‘following_url’: ‘https://api.github.com/user/following{/target}’, ‘gists_url’: ‘https://api.github.com/gists{/gist_id}’, ‘hub_url’: ‘https://api.github.com/hub’, ‘issue_search_url’: ‘https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}’, ‘issues_url’: ‘https://api.github.com/issues’, ‘keys_url’: ‘https://api.github.com/user/keys’, ‘notifications_url’: ‘https://api.github.com/notifications’, ‘organization_repositories_url’: ‘https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}’, ‘organization_url’: ‘https://api.github.com/orgs/{org}’, ‘public_gists_url’: ‘https://api.github.com/gists/public’, ‘rate_limit_url’: ‘https://api.github.com/rate_limit’, ‘repository_url’: ‘https://api.github.com/repos/{owner}/{repo}’, ‘repository_search_url’: ‘https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}’, ‘current_user_repositories_url’: ‘https://api.github.com/user/repos{?type,page,per_page,sort}’, ‘starred_url’: ‘https://api.github.com/user/starred{/owner}{/repo}’, ‘starred_gists_url’: ‘https://api.github.com/gists/starred’, ‘team_url’: ‘https://api.github.com/teams’, ‘user_url’: ‘https://api.github.com/users/{user}’, ‘user_organizations_url’: ‘https://api.github.com/user/orgs’, ‘user_repositories_url’: ‘https://api.github.com/users/{user}/repos{?type,page,per_page,sort}’, ‘user_search_url’: ‘https://api.github.com/search/users?q={query}{&page,per_page,sort,order}’}

Тип полученного значения из .json(), является словарем. Это значит, что доступ к его содержимому можно получить по ключу.

Коды состояния и тело сообщения предоставляют огромный диапазон возможностей. Однако, для их оптимального использования требуется изучить метаданные и заголовки HTTP.

HTTP заголовки ответов на запрос могут предоставить определенную полезную информацию. Это может быть тип содержимого ответного пейлоада, а также ограничение по времени для кеширования ответа. Для просмотра HTTP заголовков загляните в атрибут .headers.

>>> response.headers

{‘Server’: ‘GitHub.com’, ‘Date’: ‘Mon, 10 Dec 2018 17:49:54 GMT’, ‘Content-Type’: ‘application/json; charset=utf-8’, ‘Transfer-Encoding’: ‘chunked’, ‘Status’: ‘200 OK’, ‘X-RateLimit-Limit’: ’60’, ‘X-RateLimit-Remaining’: ’59’, ‘X-RateLimit-Reset’: ‘1544467794’, ‘Cache-Control’: ‘public, max-age=60, s-maxage=60’, ‘Vary’: ‘Accept’, ‘ETag’: ‘W/»7dc470913f1fe9bb6c7355b50a0737bc»‘, ‘X-GitHub-Media-Type’: ‘github.v3; format=json’, ‘Access-Control-Expose-Headers’: ‘ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type’, ‘Access-Control-Allow-Origin’: ‘*’, ‘Strict-Transport-Security’: ‘max-age=31536000; includeSubdomains; preload’, ‘X-Frame-Options’: ‘deny’, ‘X-Content-Type-Options’: ‘nosniff’, ‘X-XSS-Protection’: ‘1; mode=block’, ‘Referrer-Policy’: ‘origin-when-cross-origin, strict-origin-when-cross-origin’, ‘Content-Security-Policy’: «default-src ‘none'», ‘Content-Encoding’: ‘gzip’, ‘X-GitHub-Request-Id’: ‘E439:4581:CF2351:1CA3E06:5C0EA741’}

.headers возвращает словарь, что позволяет получить доступ к значению заголовка HTTP по ключу. Например, для просмотра типа содержимого ответного пейлоада, требуется использовать Content-Type.

>>> response.headers[‘Content-Type’]

‘application/json; charset=utf-8’

У объектов словарей в качестве заголовков есть своим особенности. Специфика HTTP предполагает, что заголовки не чувствительны к регистру. Это значит, что при получении доступа к заголовкам можно не беспокоится о том, использованы строчным или прописные буквы.

>>> response.headers[‘content-type’]

‘application/json; charset=utf-8’

При использовании ключей 'content-type' и 'Content-Type' результат будет получен один и тот же.

Это была основная информация, требуемая для работы с Response. Были задействованы главные атрибуты и методы, а также представлены примеры их использования. В дальнейшем будет показано, как изменится ответ после настройки запроса GET.

Python Requests параметры запроса

Наиболее простым способом настроить запрос GET является передача значений через параметры строки запроса в URL. При использовании метода get(), данные передаются в params. Например, для того, чтобы посмотреть на библиотеку requests можно использовать Search API на GitHub.

import requests

# Поиск местонахождения для запросов на GitHub

response = requests.get(

    ‘https://api.github.com/search/repositories’,

    params={‘q’: ‘requests+language:python’},

)

# Анализ некоторых атрибутов местонахождения запросов

json_response = response.json()

repository = json_response[‘items’][0]

print(f‘Repository name: {repository[«name»]}’)  # Python 3.6+

print(f‘Repository description: {repository[«description»]}’)  # Python 3.6+

Передавая словарь {'q': 'requests+language:python'} в параметр params, который является частью .get(), можно изменить ответ, что был получен при использовании Search API.

Можно передать параметры в get() в форме словаря, как было показано выше. Также можно использовать список кортежей.

>>> requests.get(

...     ‘https://api.github.com/search/repositories’,

...     params=[(‘q’, ‘requests+language:python’)],

... )

<Response [200]>

Также можно передать значение в байтах.

>>> requests.get(

...     ‘https://api.github.com/search/repositories’,

...     params=b‘q=requests+language:python’,

... )

<Response [200]>

Строки запроса полезны для уточнения параметров в запросах GET. Также можно настроить запросы при помощи добавления или изменения заголовков отправленных сообщений.

Для изменения HTTP заголовка требуется передать словарь данного HTTP заголовка в get() при помощи использования параметра headers. Например, можно изменить предыдущий поисковой запрос, подсветив совпадения в результате. Для этого в заголовке Accept медиа тип уточняется при помощи text-match.

import requests

response = requests.get(

    ‘https://api.github.com/search/repositories’,

    params={‘q’: ‘requests+language:python’},

    headers={‘Accept’: ‘application/vnd.github.v3.text-match+json’},

)

# просмотр нового массива `text-matches` с предоставленными данными

# о поиске в пределах результатов

json_response = response.json()

repository = json_response[‘items’][0]

print(f‘Text matches: {repository[«text_matches»]}’)

Заголовок Accept сообщает серверу о типах контента, который можно использовать в рассматриваемом приложении. Здесь подразумевается, что все совпадения будут подсвечены, для чего в заголовке используется значение application/vnd.github.v3.text-match+json. Это уникальный заголовок Accept для GitHub. В данном случае содержимое представлено в специальном JSON формате.

Перед более глубоким изучением способов редактирования запросов, будет не лишним остановиться на некоторых других методах HTTP.

Примеры HTTP методов в Requests

Помимо GET, большой популярностью пользуются такие методы, как POST, PUT, DELETE, HEAD, PATCH и OPTIONS. Для каждого из этих методов существует своя сигнатура, которая очень похожа на метод get().

>>> requests.post(‘https://httpbin.org/post’, data={‘key’:‘value’})

>>> requests.put(‘https://httpbin.org/put’, data={‘key’:‘value’})

>>> requests.delete(‘https://httpbin.org/delete’)

>>> requests.head(‘https://httpbin.org/get’)

>>> requests.patch(‘https://httpbin.org/patch’, data={‘key’:‘value’})

>>> requests.options(‘https://httpbin.org/get’)

Каждая функция создает запрос к httpbin сервису, используя при этом ответный HTTP метод. Результат каждого метода можно изучить способом, который был использован в предыдущих примерах.

>>> response = requests.head(‘https://httpbin.org/get’)

>>> response.headers[‘Content-Type’]

‘application/json’

>>> response = requests.delete(‘https://httpbin.org/delete’)

>>> json_response = response.json()

>>> json_response[‘args’]

{}

При использовании каждого из данных методов в Response могут быть возвращены заголовки, тело запроса, коды состояния и многие другие аспекты. Методы POST, PUT и PATCH в дальнейшем будут описаны более подробно.

Python Requests тело сообщения

В соответствии со спецификацией HTTP запросы POST, PUT и PATCH передают информацию через тело сообщения, а не через параметры строки запроса. Используя requests, можно передать данные в параметр data.

В свою очередь data использует словарь, список кортежей, байтов или объект файла. Это особенно важно, так как может возникнуть необходимость адаптации отправляемых с запросом данных в соответствии с определенными параметрами сервера.

К примеру, если тип содержимого запроса application/x-www-form-urlencoded, можно отправить данные формы в виде словаря.

>>> requests.post(‘https://httpbin.org/post’, data={‘key’:‘value’})

<Response [200]>

Ту же самую информацию также можно отправить в виде списка кортежей.

>>> requests.post(‘https://httpbin.org/post’, data=[(‘key’, ‘value’)])

<Response [200]>

В том случае, если требуется отравить данные JSON, можно использовать параметр json. При передачи данных JSON через json, requests произведет сериализацию данных и добавит правильный Content-Type заголовок.

Стоит взять на заметку сайт httpbin.org. Это чрезвычайно полезный ресурс, созданный человеком, который внедрил использование requests – Кеннетом Рейтцом. Данный сервис предназначен для тестовых запросов. Здесь можно составить пробный запрос и получить ответ с требуемой информацией. В качестве примера рассмотрим базовый запрос с использованием POST.

>>> response = requests.post(‘https://httpbin.org/post’, json={‘key’:‘value’})

>>> json_response = response.json()

>>> json_response[‘data’]

‘{«key»: «value»}’

>>> json_response[‘headers’][‘Content-Type’]

‘application/json’

Здесь видно, что сервер получил данные и HTTP заголовки, отправленные вместе с запросом. requests также предоставляет информацию в форме PreparedRequest.

Python Requests анализ запроса

При составлении запроса стоит иметь в виду, что перед его фактической отправкой на целевой сервер библиотека requests выполняет определенную подготовку. Подготовка запроса включает в себя такие вещи, как проверка заголовков и сериализация содержимого JSON.

Если открыть .request, можно просмотреть PreparedRequest.

>>> response = requests.post(‘https://httpbin.org/post’, json={‘key’:‘value’})

>>> response.request.headers[‘Content-Type’]

‘application/json’

>>> response.request.url

‘https://httpbin.org/post’

>>> response.request.body

b‘{«key»: «value»}’

Проверка PreparedRequest открывает доступ ко всей информации о выполняемом запросе. Это может быть пейлоад, URL, заголовки, аутентификация и многое другое.

У всех описанных ранее типов запросов была одна общая черта – они представляли собой неаутентифицированные запросы к публичным API. Однако, подобающее большинство служб, с которыми может столкнуться пользователь, запрашивают аутентификацию.

Python Requests аутентификация HTTP AUTH

Аутентификация помогает сервису понять, кто вы. Как правило, вы предоставляете свои учетные данные на сервер, передавая данные через заголовок Authorization или пользовательский заголовок, определенной службы. Все функции запроса, которые вы видели до этого момента, предоставляют параметр с именем auth, который позволяет вам передавать свои учетные данные.

Одним из примеров API, который требует аутентификации, является Authenticated User API на GitHub. Это конечная точка веб-сервиса, которая предоставляет информацию о профиле аутентифицированного пользователя. Чтобы отправить запрос API-интерфейсу аутентифицированного пользователя, вы можете передать свое имя пользователя и пароль на GitHub через кортеж в get().

>>> from getpass import getpass

>>> requests.get(‘https://api.github.com/user’, auth=(‘username’, getpass()))

<Response [200]>

Запрос выполнен успешно, если учетные данные, которые вы передали в кортеже auth, действительны. Если вы попытаетесь сделать этот запрос без учетных данных, вы увидите, что код состояния 401 Unauthorized.

>>> requests.get(‘https://api.github.com/user’)

<Response [401]>

Когда вы передаете имя пользователя и пароль в кортеже параметру auth, вы используете учетные данные при помощи базовой схемы аутентификации HTTP.

Таким образом, вы можете создать тот же запрос, передав подробные учетные данные базовой аутентификации, используя HTTPBasicAuth.

>>> from requests.auth import HTTPBasicAuth

>>> from getpass import getpass

>>> requests.get(

...     ‘https://api.github.com/user’,

...     auth=HTTPBasicAuth(‘username’, getpass())

... )

<Response [200]>

Хотя вам не нужно явно указывать обычную аутентификацию, может потребоваться аутентификация с использованием другого метода. requests предоставляет другие методы аутентификации, например, HTTPDigestAuth и HTTPProxyAuth.

Вы даже можете предоставить свой собственный механизм аутентификации. Для этого необходимо сначала создать подкласс AuthBase. Затем происходит имплементация __call__().

import requests

from requests.auth import AuthBase

class TokenAuth(AuthBase):

    «»»Implements a custom authentication scheme.»»»

    def __init__(self, token):

        self.token = token

    def __call__(self, r):

        «»»Attach an API token to a custom auth header.»»»

        r.headers[‘X-TokenAuth’] = f‘{self.token}’  # Python 3.6+

        return r

requests.get(‘https://httpbin.org/get’, auth=TokenAuth(‘12345abcde-token’))

Здесь пользовательский механизм TokenAuth получает специальный токен. Затем этот токен включается заголовок X-TokenAuth запроса.

Плохие механизмы аутентификации могут привести к уязвимостям безопасности, поэтому, если службе по какой-то причине не нужен настраиваемый механизм аутентификации, вы всегда можете использовать проверенную схему аутентификации, такую как Basic или OAuth.

Пока вы думаете о безопасности, давайте рассмотрим использование requests в SSL сертификатах.

Python Requests проверка SSL сертификата

Всякий раз, когда данные, которые вы пытаетесь отправить или получить, являются конфиденциальными, безопасность важна. Вы общаетесь с защищенными сайтами через HTTP, устанавливая зашифрованное соединение с использованием SSL, что означает, что проверка SSL сертификата целевого сервера имеет решающее значение.

Хорошей новостью является то, что requests по умолчанию все делает сам. Однако в некоторых случаях необходимо внести определенные поправки.

Если требуется отключить проверку SSL-сертификата, параметру verify функции запроса можно присвоить значение False.

>>> requests.get(‘https://api.github.com’, verify=False)

InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advancedusage.html#ssl-warnings

  InsecureRequestWarning)

<Response [200]>

В случае небезопасного запроса requests предупреждает о возможности потери информации и просит сохранить данные или отказаться от запроса.

Примечание. Для предоставления сертификатов requests использует пакет, который вызывается certifi. Это дает понять requests, каким ответам можно доверять. Поэтому вам следует часто обновлять certifi, чтобы обеспечить максимальную безопасность ваших соединений.

Python Requests производительность приложений

При использовании requests, особенно в среде приложений, важно учитывать влияние на производительность. Такие функции, как контроль таймаута, сеансы и ограничения повторных попыток, могут помочь обеспечить бесперебойную работу приложения.

Таймауты

Когда вы отправляете встроенный запрос во внешнюю службу, вашей системе нужно будет дождаться ответа, прежде чем двигаться дальше. Если ваше приложение слишком долго ожидает ответа, запросы к службе могут быть сохранены, пользовательский интерфейс может пострадать или фоновые задания могут зависнуть.

По умолчанию в requests на ответ время не ограничено, и весь процесс может занять значительный промежуток. По этой причине вы всегда должны указывать время ожидания, чтобы такого не происходило. Чтобы установить время ожидания запроса, используйте параметр timeout. timeout может быть целым числом или числом с плавающей точкой, представляющим количество секунд ожидания ответа до истечения времени ожидания.

>>> requests.get(‘https://api.github.com’, timeout=1)

<Response [200]>

>>> requests.get(‘https://api.github.com’, timeout=3.05)

<Response [200]>

В первом примере запрос истекает через 1 секунду. Во втором примере запрос истекает через 3,05 секунды.

Вы также можете передать кортеж. Это – таймаут соединения (время, за которое клиент может установить соединение с сервером), а второй – таймаут чтения (время ожидания ответа, как только ваш клиент установил соединение):

>>> requests.get(‘https://api.github.com’, timeout=(2, 5))

<Response [200]>

Если запрос устанавливает соединение в течение 2 секунд и получает данные в течение 5 секунд после установления соединения, то ответ будет возвращен, как это было раньше. Если время ожидания истекло, функция вызовет исключение Timeout.

import requests

from requests.exceptions import Timeout

try:

    response = requests.get(‘https://api.github.com’, timeout=1)

except Timeout:

    print(‘The request timed out’)

else:

    print(‘The request did not time out’)

Ваша программа может поймать исключение Timeout и ответить соответственно.

Объект Session в Requests

До сих пор вы имели дело с requests API высокого уровня, такими как get() и post(). Эти функции являются абстракцией того, что происходит, когда вы делаете свои запросы. Они скрывают детали реализации, такие как управление соединениями, так что вам не нужно о них беспокоиться.

Под этими абстракциями находится класс под названием Session. Если вам необходимо настроить контроль над выполнением запросов или повысить производительность ваших запросов, вам может потребоваться использовать Session напрямую.

Сессии используются для сохранения параметров в запросах.

Например, если вы хотите использовать одну и ту же аутентификацию для нескольких запросов, вы можете использовать сеанс:

import requests

from getpass import getpass

# используя менеджер контента, можно убедиться, что ресурсы, применимые

# во время сессии будут свободны после использования

with requests.Session() as session:

    session.auth = (‘username’, getpass())

    # Instead of requests.get(), you’ll use session.get()

    response = session.get(‘https://api.github.com/user’)

# здесь можно изучить ответ

print(response.headers)

print(response.json())

Каждый раз, когда вы делаете запрос session, после того как он был инициализирован с учетными данными аутентификации, учетные данные будут сохраняться.

Первичная оптимизация производительности сеансов происходит в форме постоянных соединений. Когда ваше приложение устанавливает соединение с сервером с помощью Session, оно сохраняет это соединение в пуле соединений. Когда ваше приложение снова хочет подключиться к тому же серверу, оно будет использовать соединение из пула, а не устанавливать новое.

HTTPAdapter — Максимальное количество повторов запроса в Requests

В случае сбоя запроса возникает необходимость сделать повторный запрос. Однако requests не будет делать это самостоятельно. Для применения функции повторного запроса требуется реализовать собственный транспортный адаптер.

Транспортные адаптеры позволяют определить набор конфигураций для каждой службы, с которой вы взаимодействуете. Предположим, вы хотите, чтобы все запросы к https://api.github.com были повторены три раза, прежде чем, наконец, появится ConnectionError. Для этого нужно построить транспортный адаптер, установить его параметр max_retries и подключить его к существующему объекту Session.

import requests

from requests.adapters import HTTPAdapter

from requests.exceptions import ConnectionError

github_adapter = HTTPAdapter(max_retries=3)

session = requests.Session()

# использование `github_adapter` для всех запросов, которые начинаются с указанным URL

session.mount(‘https://api.github.com’, github_adapter)

try:

    session.get(‘https://api.github.com’)

except ConnectionError as ce:

    print(ce)

При установке HTTPAdapter, github_adapter к session, session будет придерживаться своей конфигурации для каждого запроса к https://api.github.com.

Таймауты, транспортные адаптеры и сессии предназначены для обеспечения эффективности используемого кода и стабильности приложения.

Заключение

Изучение библиотеки Python requests является очень трудоемким процессом.

После разбора данных в статье примеров можно научиться тому, как:

  • Создавать запросы, используя различные методы HTTPGET, POST и PUT;
  • Настраивать свои запросы, изменив заголовки, аутентификацию, строки запросов и тела сообщений;
  • Проверять данные, которые были отправлены на сервер, а также те данные, которые сервер отправил обратно;
  • Работать с проверкой SSL сертификата;
  • Эффективно использовать requests, max_retries, timeout, Sessions и транспортные адаптеры.

Грамотное использование requests позволит наиболее эффективно настроить разрабатываемые приложения, исследуя широкий спектр веб-сервисов и данных, опубликованных на них.

  • Данная статья является переводом статьи: Python’s Requests Library (Guide)
  • Изображение статьи принадлежит сайту © RealPython

Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.

E-mail: vasile.buldumac@ati.utm.md

Образование
Universitatea Tehnică a Moldovei (utm.md)

  • 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
  • 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»

Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Making HTTP Requests With Python

The requests library is the de facto standard for making HTTP requests in Python. It abstracts the complexities of making requests behind a beautiful, simple API so that you can focus on interacting with services and consuming data in your application.

Throughout this article, you’ll see some of the most useful features that requests has to offer as well as how to customize and optimize those features for different situations you may come across. You’ll also learn how to use requests in an efficient way as well as how to prevent requests to external services from slowing down your application.

In this tutorial, you’ll learn how to:

  • Make requests using the most common HTTP methods
  • Customize your requests’ headers and data, using the query string and message body
  • Inspect data from your requests and responses
  • Make authenticated requests
  • Configure your requests to help prevent your application from backing up or slowing down

Though I’ve tried to include as much information as you need to understand the features and examples included in this article, I do assume a very basic general knowledge of HTTP. That said, you still may be able to follow along fine anyway.

Now that that is out of the way, let’s dive in and see how you can use requests in your application!

Getting Started With requests

Let’s begin by installing the requests library. To do so, run the following command:

If you prefer to use Pipenv for managing Python packages, you can run the following:

$ pipenv install requests

Once requests is installed, you can use it in your application. Importing requests looks like this:

Now that you’re all set up, it’s time to begin your journey through requests. Your first goal will be learning how to make a GET request.

The GET Request

HTTP methods such as GET and POST, determine which action you’re trying to perform when making an HTTP request. Besides GET and POST, there are several other common methods that you’ll use later in this tutorial.

One of the most common HTTP methods is GET. The GET method indicates that you’re trying to get or retrieve data from a specified resource. To make a GET request, invoke requests.get().

To test this out, you can make a GET request to GitHub’s Root REST API by calling get() with the following URL:

>>>

>>> requests.get('https://api.github.com')
<Response [200]>

Congratulations! You’ve made your first request. Let’s dive a little deeper into the response of that request.

The Response

A Response is a powerful object for inspecting the results of the request. Let’s make that same request again, but this time store the return value in a variable so that you can get a closer look at its attributes and behaviors:

>>>

>>> response = requests.get('https://api.github.com')

In this example, you’ve captured the return value of get(), which is an instance of Response, and stored it in a variable called response. You can now use response to see a lot of information about the results of your GET request.

Status Codes

The first bit of information that you can gather from Response is the status code. A status code informs you of the status of the request.

For example, a 200 OK status means that your request was successful, whereas a 404 NOT FOUND status means that the resource you were looking for was not found. There are many other possible status codes as well to give you specific insights into what happened with your request.

By accessing .status_code, you can see the status code that the server returned:

>>>

>>> response.status_code
200

.status_code returned a 200, which means your request was successful and the server responded with the data you were requesting.

Sometimes, you might want to use this information to make decisions in your code:

if response.status_code == 200:
    print('Success!')
elif response.status_code == 404:
    print('Not Found.')

With this logic, if the server returns a 200 status code, your program will print Success!. If the result is a 404, your program will print Not Found.

requests goes one step further in simplifying this process for you. If you use a Response instance in a conditional expression, it will evaluate to True if the status code was between 200 and 400, and False otherwise.

Therefore, you can simplify the last example by rewriting the if statement:

if response:
    print('Success!')
else:
    print('An error has occurred.')

Keep in mind that this method is not verifying that the status code is equal to 200. The reason for this is that other status codes within the 200 to 400 range, such as 204 NO CONTENT and 304 NOT MODIFIED, are also considered successful in the sense that they provide some workable response.

For example, the 204 tells you that the response was successful, but there’s no content to return in the message body.

So, make sure you use this convenient shorthand only if you want to know if the request was generally successful and then, if necessary, handle the response appropriately based on the status code.

Let’s say you don’t want to check the response’s status code in an if statement. Instead, you want to raise an exception if the request was unsuccessful. You can do this using .raise_for_status():

import requests
from requests.exceptions import HTTPError

for url in ['https://api.github.com', 'https://api.github.com/invalid']:
    try:
        response = requests.get(url)

        # If the response was successful, no Exception will be raised
        response.raise_for_status()
    except HTTPError as http_err:
        print(f'HTTP error occurred: {http_err}')  # Python 3.6
    except Exception as err:
        print(f'Other error occurred: {err}')  # Python 3.6
    else:
        print('Success!')

If you invoke .raise_for_status(), an HTTPError will be raised for certain status codes. If the status code indicates a successful request, the program will proceed without that exception being raised.

Now, you know a lot about how to deal with the status code of the response you got back from the server. However, when you make a GET request, you rarely only care about the status code of the response. Usually, you want to see more. Next, you’ll see how to view the actual data that the server sent back in the body of the response.

Content

The response of a GET request often has some valuable information, known as a payload, in the message body. Using the attributes and methods of Response, you can view the payload in a variety of different formats.

To see the response’s content in bytes, you use .content:

>>>

>>> response = requests.get('https://api.github.com')
>>> response.content
b'{"current_user_url":"https://api.github.com/user","current_user_authorizations_html_url":"https://github.com/settings/connections/applications{/client_id}","authorizations_url":"https://api.github.com/authorizations","code_search_url":"https://api.github.com/search/code?q={query}{&page,per_page,sort,order}","commit_search_url":"https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}","emails_url":"https://api.github.com/user/emails","emojis_url":"https://api.github.com/emojis","events_url":"https://api.github.com/events","feeds_url":"https://api.github.com/feeds","followers_url":"https://api.github.com/user/followers","following_url":"https://api.github.com/user/following{/target}","gists_url":"https://api.github.com/gists{/gist_id}","hub_url":"https://api.github.com/hub","issue_search_url":"https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}","issues_url":"https://api.github.com/issues","keys_url":"https://api.github.com/user/keys","notifications_url":"https://api.github.com/notifications","organization_repositories_url":"https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}","organization_url":"https://api.github.com/orgs/{org}","public_gists_url":"https://api.github.com/gists/public","rate_limit_url":"https://api.github.com/rate_limit","repository_url":"https://api.github.com/repos/{owner}/{repo}","repository_search_url":"https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}","current_user_repositories_url":"https://api.github.com/user/repos{?type,page,per_page,sort}","starred_url":"https://api.github.com/user/starred{/owner}{/repo}","starred_gists_url":"https://api.github.com/gists/starred","team_url":"https://api.github.com/teams","user_url":"https://api.github.com/users/{user}","user_organizations_url":"https://api.github.com/user/orgs","user_repositories_url":"https://api.github.com/users/{user}/repos{?type,page,per_page,sort}","user_search_url":"https://api.github.com/search/users?q={query}{&page,per_page,sort,order}"}'

While .content gives you access to the raw bytes of the response payload, you will often want to convert them into a string using a character encoding such as UTF-8. response will do that for you when you access .text:

>>>

>>> response.text
'{"current_user_url":"https://api.github.com/user","current_user_authorizations_html_url":"https://github.com/settings/connections/applications{/client_id}","authorizations_url":"https://api.github.com/authorizations","code_search_url":"https://api.github.com/search/code?q={query}{&page,per_page,sort,order}","commit_search_url":"https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}","emails_url":"https://api.github.com/user/emails","emojis_url":"https://api.github.com/emojis","events_url":"https://api.github.com/events","feeds_url":"https://api.github.com/feeds","followers_url":"https://api.github.com/user/followers","following_url":"https://api.github.com/user/following{/target}","gists_url":"https://api.github.com/gists{/gist_id}","hub_url":"https://api.github.com/hub","issue_search_url":"https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}","issues_url":"https://api.github.com/issues","keys_url":"https://api.github.com/user/keys","notifications_url":"https://api.github.com/notifications","organization_repositories_url":"https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}","organization_url":"https://api.github.com/orgs/{org}","public_gists_url":"https://api.github.com/gists/public","rate_limit_url":"https://api.github.com/rate_limit","repository_url":"https://api.github.com/repos/{owner}/{repo}","repository_search_url":"https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}","current_user_repositories_url":"https://api.github.com/user/repos{?type,page,per_page,sort}","starred_url":"https://api.github.com/user/starred{/owner}{/repo}","starred_gists_url":"https://api.github.com/gists/starred","team_url":"https://api.github.com/teams","user_url":"https://api.github.com/users/{user}","user_organizations_url":"https://api.github.com/user/orgs","user_repositories_url":"https://api.github.com/users/{user}/repos{?type,page,per_page,sort}","user_search_url":"https://api.github.com/search/users?q={query}{&page,per_page,sort,order}"}'

Because the decoding of bytes to a str requires an encoding scheme, requests will try to guess the encoding based on the response’s headers if you do not specify one. You can provide an explicit encoding by setting .encoding before accessing .text:

>>>

>>> response.encoding = 'utf-8' # Optional: requests infers this internally
>>> response.text
'{"current_user_url":"https://api.github.com/user","current_user_authorizations_html_url":"https://github.com/settings/connections/applications{/client_id}","authorizations_url":"https://api.github.com/authorizations","code_search_url":"https://api.github.com/search/code?q={query}{&page,per_page,sort,order}","commit_search_url":"https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}","emails_url":"https://api.github.com/user/emails","emojis_url":"https://api.github.com/emojis","events_url":"https://api.github.com/events","feeds_url":"https://api.github.com/feeds","followers_url":"https://api.github.com/user/followers","following_url":"https://api.github.com/user/following{/target}","gists_url":"https://api.github.com/gists{/gist_id}","hub_url":"https://api.github.com/hub","issue_search_url":"https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}","issues_url":"https://api.github.com/issues","keys_url":"https://api.github.com/user/keys","notifications_url":"https://api.github.com/notifications","organization_repositories_url":"https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}","organization_url":"https://api.github.com/orgs/{org}","public_gists_url":"https://api.github.com/gists/public","rate_limit_url":"https://api.github.com/rate_limit","repository_url":"https://api.github.com/repos/{owner}/{repo}","repository_search_url":"https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}","current_user_repositories_url":"https://api.github.com/user/repos{?type,page,per_page,sort}","starred_url":"https://api.github.com/user/starred{/owner}{/repo}","starred_gists_url":"https://api.github.com/gists/starred","team_url":"https://api.github.com/teams","user_url":"https://api.github.com/users/{user}","user_organizations_url":"https://api.github.com/user/orgs","user_repositories_url":"https://api.github.com/users/{user}/repos{?type,page,per_page,sort}","user_search_url":"https://api.github.com/search/users?q={query}{&page,per_page,sort,order}"}'

If you take a look at the response, you’ll see that it is actually serialized JSON content. To get a dictionary, you could take the str you retrieved from .text and deserialize it using json.loads(). However, a simpler way to accomplish this task is to use .json():

>>>

>>> response.json()
{'current_user_url': 'https://api.github.com/user', 'current_user_authorizations_html_url': 'https://github.com/settings/connections/applications{/client_id}', 'authorizations_url': 'https://api.github.com/authorizations', 'code_search_url': 'https://api.github.com/search/code?q={query}{&page,per_page,sort,order}', 'commit_search_url': 'https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}', 'emails_url': 'https://api.github.com/user/emails', 'emojis_url': 'https://api.github.com/emojis', 'events_url': 'https://api.github.com/events', 'feeds_url': 'https://api.github.com/feeds', 'followers_url': 'https://api.github.com/user/followers', 'following_url': 'https://api.github.com/user/following{/target}', 'gists_url': 'https://api.github.com/gists{/gist_id}', 'hub_url': 'https://api.github.com/hub', 'issue_search_url': 'https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}', 'issues_url': 'https://api.github.com/issues', 'keys_url': 'https://api.github.com/user/keys', 'notifications_url': 'https://api.github.com/notifications', 'organization_repositories_url': 'https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}', 'organization_url': 'https://api.github.com/orgs/{org}', 'public_gists_url': 'https://api.github.com/gists/public', 'rate_limit_url': 'https://api.github.com/rate_limit', 'repository_url': 'https://api.github.com/repos/{owner}/{repo}', 'repository_search_url': 'https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}', 'current_user_repositories_url': 'https://api.github.com/user/repos{?type,page,per_page,sort}', 'starred_url': 'https://api.github.com/user/starred{/owner}{/repo}', 'starred_gists_url': 'https://api.github.com/gists/starred', 'team_url': 'https://api.github.com/teams', 'user_url': 'https://api.github.com/users/{user}', 'user_organizations_url': 'https://api.github.com/user/orgs', 'user_repositories_url': 'https://api.github.com/users/{user}/repos{?type,page,per_page,sort}', 'user_search_url': 'https://api.github.com/search/users?q={query}{&page,per_page,sort,order}'}

The type of the return value of .json() is a dictionary, so you can access values in the object by key.

You can do a lot with status codes and message bodies. But, if you need more information, like metadata about the response itself, you’ll need to look at the response’s headers.

Query String Parameters

One common way to customize a GET request is to pass values through query string parameters in the URL. To do this using get(), you pass data to params. For example, you can use GitHub’s Search API to look for the requests library:

import requests

# Search GitHub's repositories for requests
response = requests.get(
    'https://api.github.com/search/repositories',
    params={'q': 'requests+language:python'},
)

# Inspect some attributes of the `requests` repository
json_response = response.json()
repository = json_response['items'][0]
print(f'Repository name: {repository["name"]}')  # Python 3.6+
print(f'Repository description: {repository["description"]}')  # Python 3.6+

By passing the dictionary {'q': 'requests+language:python'} to the params parameter of .get(), you are able to modify the results that come back from the Search API.

You can pass params to get() in the form of a dictionary, as you have just done, or as a list of tuples:

>>>

>>> requests.get(
...     'https://api.github.com/search/repositories',
...     params=[('q', 'requests+language:python')],
... )
<Response [200]>

You can even pass the values as bytes:

>>>

>>> requests.get(
...     'https://api.github.com/search/repositories',
...     params=b'q=requests+language:python',
... )
<Response [200]>

Query strings are useful for parameterizing GET requests. You can also customize your requests by adding or modifying the headers you send.

Other HTTP Methods

Aside from GET, other popular HTTP methods include POST, PUT, DELETE, HEAD, PATCH, and OPTIONS. requests provides a method, with a similar signature to get(), for each of these HTTP methods:

>>>

>>> requests.post('https://httpbin.org/post', data={'key':'value'})
>>> requests.put('https://httpbin.org/put', data={'key':'value'})
>>> requests.delete('https://httpbin.org/delete')
>>> requests.head('https://httpbin.org/get')
>>> requests.patch('https://httpbin.org/patch', data={'key':'value'})
>>> requests.options('https://httpbin.org/get')

Each function call makes a request to the httpbin service using the corresponding HTTP method. For each method, you can inspect their responses in the same way you did before:

>>>

>>> response = requests.head('https://httpbin.org/get')
>>> response.headers['Content-Type']
'application/json'

>>> response = requests.delete('https://httpbin.org/delete')
>>> json_response = response.json()
>>> json_response['args']
{}

Headers, response bodies, status codes, and more are returned in the Response for each method. Next you’ll take a closer look at the POST, PUT, and PATCH methods and learn how they differ from the other request types.

The Message Body

According to the HTTP specification, POST, PUT, and the less common PATCH requests pass their data through the message body rather than through parameters in the query string. Using requests, you’ll pass the payload to the corresponding function’s data parameter.

data takes a dictionary, a list of tuples, bytes, or a file-like object. You’ll want to adapt the data you send in the body of your request to the specific needs of the service you’re interacting with.

For example, if your request’s content type is application/x-www-form-urlencoded, you can send the form data as a dictionary:

>>>

>>> requests.post('https://httpbin.org/post', data={'key':'value'})
<Response [200]>

You can also send that same data as a list of tuples:

>>>

>>> requests.post('https://httpbin.org/post', data=[('key', 'value')])
<Response [200]>

If, however, you need to send JSON data, you can use the json parameter. When you pass JSON data via json, requests will serialize your data and add the correct Content-Type header for you.

httpbin.org is a great resource created by the author of requests, Kenneth Reitz. It’s a service that accepts test requests and responds with data about the requests. For instance, you can use it to inspect a basic POST request:

>>>

>>> response = requests.post('https://httpbin.org/post', json={'key':'value'})
>>> json_response = response.json()
>>> json_response['data']
'{"key": "value"}'
>>> json_response['headers']['Content-Type']
'application/json'

You can see from the response that the server received your request data and headers as you sent them. requests also provides this information to you in the form of a PreparedRequest.

Inspecting Your Request

When you make a request, the requests library prepares the request before actually sending it to the destination server. Request preparation includes things like validating headers and serializing JSON content.

You can view the PreparedRequest by accessing .request:

>>>

>>> response = requests.post('https://httpbin.org/post', json={'key':'value'})
>>> response.request.headers['Content-Type']
'application/json'
>>> response.request.url
'https://httpbin.org/post'
>>> response.request.body
b'{"key": "value"}'

Inspecting the PreparedRequest gives you access to all kinds of information about the request being made such as payload, URL, headers, authentication, and more.

So far, you’ve made a lot of different kinds of requests, but they’ve all had one thing in common: they’re unauthenticated requests to public APIs. Many services you may come across will want you to authenticate in some way.

Authentication

Authentication helps a service understand who you are. Typically, you provide your credentials to a server by passing data through the Authorization header or a custom header defined by the service. All the request functions you’ve seen to this point provide a parameter called auth, which allows you to pass your credentials.

One example of an API that requires authentication is GitHub’s Authenticated User API. This endpoint provides information about the authenticated user’s profile. To make a request to the Authenticated User API, you can pass your GitHub username and password in a tuple to get():

>>>

>>> from getpass import getpass
>>> requests.get('https://api.github.com/user', auth=('username', getpass()))
<Response [200]>

The request succeeded if the credentials you passed in the tuple to auth are valid. If you try to make this request with no credentials, you’ll see that the status code is 401 Unauthorized:

>>>

>>> requests.get('https://api.github.com/user')
<Response [401]>

When you pass your username and password in a tuple to the auth parameter, requests is applying the credentials using HTTP’s Basic access authentication scheme under the hood.

Therefore, you could make the same request by passing explicit Basic authentication credentials using HTTPBasicAuth:

>>>

>>> from requests.auth import HTTPBasicAuth
>>> from getpass import getpass
>>> requests.get(
...     'https://api.github.com/user',
...     auth=HTTPBasicAuth('username', getpass())
... )
<Response [200]>

Though you don’t need to be explicit for Basic authentication, you may want to authenticate using another method. requests provides other methods of authentication out of the box such as HTTPDigestAuth and HTTPProxyAuth.

You can even supply your own authentication mechanism. To do so, you must first create a subclass of AuthBase. Then, you implement __call__():

import requests
from requests.auth import AuthBase

class TokenAuth(AuthBase):
    """Implements a custom authentication scheme."""

    def __init__(self, token):
        self.token = token

    def __call__(self, r):
        """Attach an API token to a custom auth header."""
        r.headers['X-TokenAuth'] = f'{self.token}'  # Python 3.6+
        return r


requests.get('https://httpbin.org/get', auth=TokenAuth('12345abcde-token'))

Here, your custom TokenAuth mechanism receives a token, then includes that token in the X-TokenAuth header of your request.

Bad authentication mechanisms can lead to security vulnerabilities, so unless a service requires a custom authentication mechanism for some reason, you’ll always want to use a tried-and-true auth scheme like Basic or OAuth.

While you’re thinking about security, let’s consider dealing with SSL Certificates using requests.

SSL Certificate Verification

Any time the data you are trying to send or receive is sensitive, security is important. The way that you communicate with secure sites over HTTP is by establishing an encrypted connection using SSL, which means that verifying the target server’s SSL Certificate is critical.

The good news is that requests does this for you by default. However, there are some cases where you might want to change this behavior.

If you want to disable SSL Certificate verification, you pass False to the verify parameter of the request function:

>>>

>>> requests.get('https://api.github.com', verify=False)
InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
  InsecureRequestWarning)
<Response [200]>

requests even warns you when you’re making an insecure request to help you keep your data safe!

Performance

When using requests, especially in a production application environment, it’s important to consider performance implications. Features like timeout control, sessions, and retry limits can help you keep your application running smoothly.

Timeouts

When you make an inline request to an external service, your system will need to wait upon the response before moving on. If your application waits too long for that response, requests to your service could back up, your user experience could suffer, or your background jobs could hang.

By default, requests will wait indefinitely on the response, so you should almost always specify a timeout duration to prevent these things from happening. To set the request’s timeout, use the timeout parameter. timeout can be an integer or float representing the number of seconds to wait on a response before timing out:

>>>

>>> requests.get('https://api.github.com', timeout=1)
<Response [200]>
>>> requests.get('https://api.github.com', timeout=3.05)
<Response [200]>

In the first request, the request will timeout after 1 second. In the second request, the request will timeout after 3.05 seconds.

You can also pass a tuple to timeout with the first element being a connect timeout (the time it allows for the client to establish a connection to the server), and the second being a read timeout (the time it will wait on a response once your client has established a connection):

>>>

>>> requests.get('https://api.github.com', timeout=(2, 5))
<Response [200]>

If the request establishes a connection within 2 seconds and receives data within 5 seconds of the connection being established, then the response will be returned as it was before. If the request times out, then the function will raise a Timeout exception:

import requests
from requests.exceptions import Timeout

try:
    response = requests.get('https://api.github.com', timeout=1)
except Timeout:
    print('The request timed out')
else:
    print('The request did not time out')

Your program can catch the Timeout exception and respond accordingly.

The Session Object

Until now, you’ve been dealing with high level requests APIs such as get() and post(). These functions are abstractions of what’s going on when you make your requests. They hide implementation details such as how connections are managed so that you don’t have to worry about them.

Underneath those abstractions is a class called Session. If you need to fine-tune your control over how requests are being made or improve the performance of your requests, you may need to use a Session instance directly.

Sessions are used to persist parameters across requests. For example, if you want to use the same authentication across multiple requests, you could use a session:

import requests
from getpass import getpass

# By using a context manager, you can ensure the resources used by
# the session will be released after use
with requests.Session() as session:
    session.auth = ('username', getpass())

    # Instead of requests.get(), you'll use session.get()
    response = session.get('https://api.github.com/user')

# You can inspect the response just like you did before
print(response.headers)
print(response.json())

Each time you make a request with session, once it has been initialized with authentication credentials, the credentials will be persisted.

The primary performance optimization of sessions comes in the form of persistent connections. When your app makes a connection to a server using a Session, it keeps that connection around in a connection pool. When your app wants to connect to the same server again, it will reuse a connection from the pool rather than establishing a new one.

Max Retries

When a request fails, you may want your application to retry the same request. However, requests will not do this for you by default. To apply this functionality, you need to implement a custom Transport Adapter.

Transport Adapters let you define a set of configurations per service you’re interacting with. For example, let’s say you want all requests to https://api.github.com to retry three times before finally raising a ConnectionError. You would build a Transport Adapter, set its max_retries parameter, and mount it to an existing Session:

import requests
from requests.adapters import HTTPAdapter
from requests.exceptions import ConnectionError

github_adapter = HTTPAdapter(max_retries=3)

session = requests.Session()

# Use `github_adapter` for all requests to endpoints that start with this URL
session.mount('https://api.github.com', github_adapter)

try:
    session.get('https://api.github.com')
except ConnectionError as ce:
    print(ce)

When you mount the HTTPAdapter, github_adapter, to session, session will adhere to its configuration for each request to https://api.github.com.

Timeouts, Transport Adapters, and sessions are for keeping your code efficient and your application resilient.

Conclusion

You’ve come a long way in learning about Python’s powerful requests library.

You’re now able to:

  • Make requests using a variety of different HTTP methods such as GET, POST, and PUT
  • Customize your requests by modifying headers, authentication, query strings, and message bodies
  • Inspect the data you send to the server and the data the server sends back to you
  • Work with SSL Certificate verification
  • Use requests effectively using max_retries, timeout, Sessions, and Transport Adapters

Because you learned how to use requests, you’re equipped to explore the wide world of web services and build awesome applications using the fascinating data they provide.

Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Making HTTP Requests With Python

Понравилась статья? Поделить с друзьями:
  • Python request connection error
  • Python redirector was called with command line arguments printing error message and exiting
  • Python raise error with traceback
  • Python raise error with message
  • Python raise error code