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
24 Дек. 2015, Python, 342318 просмотров,
Стандартная библиотека Python имеет ряд готовых модулей по работе с HTTP.
- urllib
- httplib
Если уж совсем хочется хардкора, то можно и сразу с socket поработать. Но у всех этих модулей есть один большой недостаток — неудобство работы.
Во-первых, большое обилие классов и функций. Во-вторых, код получается вовсе не pythonic. Многие программисты любят Python за его элегантность и простоту, поэтому и был создан модуль, призванный решать проблему существующих и имя ему requests или HTTP For Humans. На момент написания данной заметки, последняя версия библиотеки — 2.9.1. С момента выхода Python версии 3.5 я дал себе негласное обещание писать новый код только на Py >= 3.5. Пора бы уже полностью перебираться на 3-ю ветку змеюки, поэтому в моих примерах print отныне является функцией, а не оператором
Что же умеет requests?
Для начала хочется показать как выглядит код работы с http, используя модули из стандартной библиотеки Python и код при работе с requests. В качестве мишени для стрельбы http запросами будет использоваться очень удобный сервис httpbin.org
>>> import urllib.request
>>> response = urllib.request.urlopen('https://httpbin.org/get')
>>> print(response.read())
b'{n "args": {}, n "headers": {n "Accept-Encoding": "identity", n "Host": "httpbin.org", n "User-Agent": "Python-urllib/3.5"n }, n "origin": "95.56.82.136", n "url": "https://httpbin.org/get"n}n'
>>> print(response.getheader('Server'))
nginx
>>> print(response.getcode())
200
>>>
Кстати, urllib.request это надстройка над «низкоуровневой» библиотекой httplib о которой я писал выше.
>>> import requests
>>> response = requests.get('https://httpbin.org/get')
>>> print(response.content)
b'{n "args": {}, n "headers": {n "Accept": "*/*", n "Accept-Encoding": "gzip, deflate", n "Host": "httpbin.org", n "User-Agent": "python-requests/2.9.1"n }, n "origin": "95.56.82.136", n "url": "https://httpbin.org/get"n}n'
>>> response.json()
{'headers': {'Accept-Encoding': 'gzip, deflate', 'User-Agent': 'python-requests/2.9.1', 'Host': 'httpbin.org', 'Accept': '*/*'}, 'args': {}, 'origin': '95.56.82.136', 'url': 'https://httpbin.org/get'}
>>> response.headers
{'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Server': 'nginx', 'Access-Control-Allow-Credentials': 'true', 'Access-Control-Allow-Origin': '*', 'Content-Length': '237', 'Date': 'Wed, 23 Dec 2015 17:56:46 GMT'}
>>> response.headers.get('Server')
'nginx'
В простых методах запросов значительных отличий у них не имеется. Но давайте взглянем на работы с Basic Auth:
>>> import urllib.request
>>> password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
>>> top_level_url = 'https://httpbin.org/basic-auth/user/passwd'
>>> password_mgr.add_password(None, top_level_url, 'user', 'passwd')
>>> handler = urllib.request.HTTPBasicAuthHandler(password_mgr)
>>> opener = urllib.request.build_opener(handler)
>>> response = opener.open(top_level_url)
>>> response.getcode()
200
>>> response.read()
b'{n "authenticated": true, n "user": "user"n}n'
>>> import requests
>>> response = requests.get('https://httpbin.org/basic-auth/user/passwd', auth=('user', 'passwd'))
>>> print(response.content)
b'{n "authenticated": true, n "user": "user"n}n'
>>> print(response.json())
{'user': 'user', 'authenticated': True}
А теперь чувствуется разница между pythonic и non-pythonic? Я думаю разница на лицо. И несмотря на тот факт, что requests ничто иное как обёртка над urllib3, а последняя является надстройкой над стандартными средствами Python, удобство написания кода в большинстве случаев является приоритетом номер один.
В requests имеется:
- Множество методов http аутентификации
- Сессии с куками
- Полноценная поддержка SSL
- Различные методы-плюшки вроде .json(), которые вернут данные в нужном формате
- Проксирование
- Грамотная и логичная работа с исключениями
О последнем пункте мне бы хотелось поговорить чуточку подробнее.
Обработка исключений в requests
При работе с внешними сервисами никогда не стоит полагаться на их отказоустойчивость. Всё упадёт рано или поздно, поэтому нам, программистам, необходимо быть всегда к этому готовыми, желательно заранее и в спокойной обстановке.
Итак, как у requests дела обстоят с различными факапами в момент сетевых соединений? Для начала определим ряд проблем, которые могут возникнуть:
- Хост недоступен. Обычно такого рода ошибка происходит из-за проблем конфигурирования DNS. (DNS lookup failure)
- «Вылет» соединения по таймауту
- Ошибки HTTP. Подробнее о HTTP кодах можно посмотреть здесь.
- Ошибки SSL соединений (обычно при наличии проблем с SSL сертификатом: просрочен, не является доверенным и т.д.)
Базовым классом-исключением в requests является RequestException. От него наследуются все остальные
- HTTPError
- ConnectionError
- Timeout
- SSLError
- ProxyError
И так далее. Полный список всех исключений можно посмотреть в requests.exceptions.
Timeout
В requests имеется 2 вида таймаут-исключений:
- ConnectTimeout — таймаут на соединения
- ReadTimeout — таймаут на чтение
>>> import requests
>>> try:
... response = requests.get('https://httpbin.org/user-agent', timeout=(0.00001, 10))
... except requests.exceptions.ConnectTimeout:
... print('Oops. Connection timeout occured!')
...
Oops. Connection timeout occured!
>>> try:
... response = requests.get('https://httpbin.org/user-agent', timeout=(10, 0.0001))
... except requests.exceptions.ReadTimeout:
... print('Oops. Read timeout occured')
... except requests.exceptions.ConnectTimeout:
... print('Oops. Connection timeout occured!')
...
Oops. Read timeout occured
ConnectionError
>>> import requests
>>> try:
... response = requests.get('http://urldoesnotexistforsure.bom')
... except requests.exceptions.ConnectionError:
... print('Seems like dns lookup failed..')
...
Seems like dns lookup failed..
HTTPError
>>> import requests
>>> try:
... response = requests.get('https://httpbin.org/status/500')
... response.raise_for_status()
... except requests.exceptions.HTTPError as err:
... print('Oops. HTTP Error occured')
... print('Response is: {content}'.format(content=err.response.content))
...
Oops. HTTP Error occured
Response is: b''
Я перечислил основные виды исключений, которые покрывают, пожалуй, 90% всех проблем, возникающих при работе с http. Главное помнить, что если мы действительно намерены отловить что-то и обработать, то это необходимо явно запрограммировать, если же нам неважен тип конкретного исключения, то можно отлавливать общий базовый класс RequestException и действовать уже от конкретного случая, например, залоггировать исключение и выкинуть его дальше наверх. Кстати, о логгировании я напишу отдельный подробный пост.
У блога появился свой Telegram канал, где я стараюсь делиться интересными находками из сети на тему разработки программного обеспечения. Велком, как говорится
Полезные «плюшки»
- httpbin.org очень полезный сервис для тестирования http клиентов, в частности удобен для тестирования нестандартного поведения сервиса
- httpie консольный http клиент (замена curl) написанный на Python
- responses mock библиотека для работы с requests
- HTTPretty mock библиотека для работы с http модулями
💌 Присоединяйтесь к рассылке
Понравился контент? Пожалуйста, подпишись на рассылку.
Содержание
- Введение в тему
- Создание get и post запроса
- Передача параметров в url
- Содержимое ответа response
- Бинарное содержимое ответа
- Содержимое ответа в json
- Необработанное содержимое ответа
- Пользовательские заголовки
- Более сложные post запросы
- Post отправка multipart encoded файла
- Коды состояния ответа
- Заголовки ответов
- Cookies
- Редиректы и история
- Тайм ауты
- Ошибки и исключения
Введение в тему
Модуль python requests – это общепринятый стандарт для работы с запросами по протоколу HTTP.
Этот модуль избавляет Вас от необходимости работать с низкоуровневыми деталями. Работа с запросами становится простой и элегантной.
В этом уроке будут рассмотрены самые полезные функций библиотеки requests и различные способы их использования.
Перед использованием модуля его необходимо установить:
Создание get и post запроса
Сперва необходимо добавить модуль Requests в Ваш код:
Создадим запрос и получим ответ, содержащий страницу и все необходимые данные о ней.
import requests
response = requests.get('https://www.google.ru/')
В переменную response попадает ответ на запрос. Благодаря этому объекту можно использовать любую информацию, относящуюся к этому ответу.
Сделать POST запрос так же очень просто:
import requests
response = requests.post('https://www.google.ru/', data = {'foo':3})
Другие виды HTTP запросов, к примеру: PUT, DELETE, и прочих, выполнить ничуть не сложнее:
import requests
response = requests.put('https://www.google.ru/', data = {'foo':3})
response = requests.delete('https://www.google.ru/')
response = requests.head('https://www.google.ru/')
response = requests.options('https://www.google.ru/')
Передача параметров в url
Иногда может быть необходимо отправить различные данные вместе с запросом URL. При ручной настройке URL, параметры выглядят как пары ключ=значение после знака «?». Например, https://www.google.ru/search?q=Python. Модуль Requests предоставляет возможность передать эти параметры как словарь, применяя аргумент params. Если вы хотите передать q = Python и foo=’bar’ ресурсу google.ru/search, вы должны использовать следующий код:
import requests
params_dict = {'q':'Python', 'foo':'bar'}
response = requests.get('https://www.google.ru/search', params=params_dict)
print(response.url)
#Вывод:
https://www.google.ru/search?q=Python&foo=bar
Здесь мы видим, что URL был сформирован именно так, как это было задумано.
Пара ключ=значение, где значение равняется None, не будет добавлена к параметрам запроса URL.
Так же есть возможность передавать в запрос список параметров:
import requests
params_dict = {'q':'Python', 'foo':['bar', 'eggs']}
response = requests.get('https://www.google.ru/search', params=params_dict)
print(response.url)
#Вывод:
https://www.google.ru/search?q=Python&foo=bar&foo=eggs
Содержимое ответа response
Код из предыдущего листинга создаёт объект Response, содержащий ответ сервера на наш запрос. Обратившись к его атрибуту .url можно просмотреть адрес, куда был направлен запрос. Атрибут .text позволяет просмотреть содержимое ответа. Вот как это работает:
import requests
params_dict = {'q':'Python'}
response = requests.get('https://www.google.ru/search', params=params_dict)
print(response.text)
#Вывод:<!doctype html><html lang="ru"><head><meta charset="UTF-8"><meta content="/images/branding/googleg/1x/googleg_standard_color_128dp.png"…
Библиотека автоматически пытается определить кодировку ответа основываясь на его заголовках. Узнать, какую кодировку выбрал модуль, можно следующим образом:
import requests
params_dict = {'q':'Python'}
response = requests.get('https://www.google.ru/search', params=params_dict)
print(response.encoding)
#Вывод:
windows-1251
Можно так же самостоятельно установить кодировку используя атрибут .encoding.
import requests
params_dict = {'q':'Python'}
response = requests.get('https://www.google.ru/search', params=params_dict)
response.encoding = 'utf-8' # указываем необходимую кодировку вручную
print(response.encoding)
#Вывод:
utf-8
Бинарное содержимое ответа
Существует возможность просмотра ответа в виде байтов:
import requests
params_dict = {'q':'Python'}
response = requests.get('https://www.google.ru/search', params=params_dict)
print(response.content)
#Вывод:
b'<!doctype html><html lang="ru"><head><meta charset="UTF-8"><meta content="/images/branding/googleg/1x/googleg_standard_color_128dp.png" …
При передаче со сжатием ответ автоматически декодируется для Вас.
Содержимое ответа в json
Так же в Requests есть встроенная обработка ответов в формате JSON:
import requests
import json
response = requests.get(‘http://api.open-notify.org/astros.json’)
print(json.dumps(response.json(), sort_keys=True, indent=4))
#Вывод:
{
«message»: «success»,
«number»: 10,
«people»: [
{
«craft»: «ISS»,
«name»: «Mark Vande Hei»
},
{
«craft»: «ISS»,
«name»: «Oleg Novitskiy»
},
…
[/dm_code_snippet]
Если ответ не является JSON, то .json выбросит исключение:
import requests
import json
response = requests.get('https://www.google.ru/search')
print(json.dumps(response.json(), sort_keys=True, indent=4))
#Вывод:
…
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
Необработанное содержимое ответа
Если Вам нужно получить доступ к ответу сервера в чистом виде на уровне сокета, обратитесь к атрибуту .raw. Для этого необходимо указать параметр stream=True в запросе. Этот параметр заставляет модуль читать данные по мере их прибытия.
import requests
response = requests.get('https://www.google.ru/', stream=True)
print(response.raw)
print('Q'*10)
print(response.raw.read(15))
#Вывод:
<urllib3.response.HTTPResponse object at 0x000001E368771FA0>
QQQQQQQQQQ
b'x1fx8bx08x00x00x00x00x00x02xffxc5[[sxdb'
Так же можно использовать метод .iter_content. Этот метод итерирует данные потокового ответа и это позволяет избежать чтения содержимого сразу в память для больших ответов. Параметр chunk_size – это количество байтов, которые он должен прочитать в памяти. Параметр chunk_size можно произвольно менять.
import requests
response = requests.get('https://www.google.ru/', stream=True)
print(response.iter_content)
print('Q'*10)
print([i for i in response.iter_content(chunk_size=256)])
#Вывод:
<bound method Response.iter_content of <Response [200]>>
QQQQQQQQQQ
[b'<!doctype html><html itemscope="" itemtype="http://sche', b'ma.org/WebPage" lang="ru"><head><meta content=…
response.iter_content будет автоматически декодировать сжатый ответ. Response.raw — чистый набор байтов, неизменённое содержимое ответа.
Пользовательские заголовки
Если необходимо установить заголовки в HTTP запросе, передайте словарь с ними в параметр headers. Значения заголовка должны быть типа string, bytestring или unicode. Имена заголовков не чувствительны к регистру символов.
В следующем примере мы устанавливаем информацию об используемом браузере:
import requests
response = requests.get('https://www.google.ru/', headers={'user-agent': 'unknown_browser'})
print(response.request.headers)
# Вывод:
{'user-agent': 'unknown_browser', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
Более сложные post запросы
Существует способ отправить данные так, будто это результат заполнения формы на сайте:
import requests
response = requests.post('https://httpbin.org/post', data={'foo': 'bar'})
print(response.text)
# Вывод:
{
"args": {},
"data": "",
"files": {},
"form": {
"foo": "bar"
},
"headers": {
…
Параметр data может иметь произвольное количество значений для каждого ключа. Для этого необходимо указать data в формате кортежа, либо в виде dict со списками значений.
import requests
response = requests.post('https://httpbin.org/post', data={'foo':['bar', 'eggs']})
print(response.json()['form'])
print('|'*10)
response = requests.post('https://httpbin.org/post', data=[('foo', 'bar'), ('foo', 'eggs')])
print(response.json()['form'])
# Вывод:
{'foo': ['bar', 'eggs']}
||||||||||
{'foo': ['bar', 'eggs']}
Если нужно отправить данные, не закодированные как данные формы, то передайте в запрос строку вместо словаря. Тогда данные отправятся в изначальном виде.
import requests
response = requests.post('https://httpbin.org/post', data={'foo': 'bar'})
print('URL:', response.request.url)
print('Body:', response.request.body)
print('-' * 10)
response = requests.post('https://httpbin.org/post', data='foo=bar')
print('URL:', response.request.url)
print('Body:', response.request.body)
# Вывод:
URL: https://httpbin.org/post
URL: https://httpbin.org/post
Body: foo=bar
----------
URL: https://httpbin.org/post
Body: foo=bar
Post отправка multipart encoded файла
Запросы упрощают загрузку файлов с многостраничным кодированием (Multipart-Encoded):
import requests
url = 'https://httpbin.org/post'
files = {'file': open('report.xls', 'rb')}
response = requests.post(url, files=files)
print(response.text)
# Вывод:
{
...
"files": {
"file": "<censored...binary...data>"
},
...
}
Вы можете установить имя файла, content_type и заголовки в явном виде:
import requests
url = 'https://httpbin.org/post'
files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})}
response = requests.post(url, files=files)
print(response.text)
# Вывод:
{
...
"files": {
"file": "<censored...binary...data>"
},
...
}
Можете отправить строки, которые будут приняты в виде файлов:
import requests
url = 'https://httpbin.org/post'
files = {'file': ('report.csv', 'some,data,to,sendnanother,row,to,sendn')}
response = requests.post(url, files=files)
print(response.text)
# Вывод:
{
...
"files": {
"file": "some,data,to,send\nanother,row,to,send\n"
},
...
}
Коды состояния ответа
Возможно, наиболее важные данные (первые – уж точно), которые вы можете получить, используя библиотеку requests, является код состояния ответа.
Так, 200 статус означает, что запрос выполнен успешно, тогда как 404 статус означает, что ресурс не найден.
Важнее всего то, с какой цифры начинается код состояния:
- 1XX — информация
- 2XX — успешно
- 3XX — перенаправление
- 4XX — ошибка клиента (ошибка на нашей стороне)
- 5XX — ошибка сервера (самые страшные коды для разработчика)
Используя атрибут .status_code можно получить статус, который вернул сервер:
import requests
response = requests.get('https://www.google.ru/')
print(response.status_code)
# Вывод:
200
.status_code вернул 200 — это означает, что запрос успешно выполнен и сервер вернул запрашиваемые данные.
При желании, такую информацию можно применить в Вашем Пайтон скрипте для принятия решений:
import requests
response = requests.get('https://www.google.ru/')
if response.status_code == 200: print('Успех!')elif response.status_code == 404: print('Страница куда-то пропала…')
# Вывод:
Успех!
Если код состояния response равен 200, то скрипт выведет «Успех!», но, если он равен 404, то скрипт вернёт «Страница куда-то пропала…».
Если применить модуль Response в условном выражении и проверить логическое значение его экземпляра (if response) то он продемонстрирует значение True, если код ответа находится в диапазоне между 200 и 400, и False во всех остальных случаях.
Упростим код из предыдущего примера:
import requests
response = requests.get('https://www.google.ru/fake/')
if response:
print('Успех!')
else:
print('Хьюстон, у нас проблемы!')
# Вывод:
Хьюстон, у нас проблемы!
Данный способ не проверяет, что код состояния равен именно 200.
Причиной этого является то, что response с кодом в диапазоне от 200 до 400, такие как 204 и 304, тоже являются успешными, ведь они возвращают обрабатываемый ответ. Следовательно, этот подход делит все запросы на успешные и неуспешные – не более того. Во многих случаях Вам потребуется более детальная обработка кодов состояния запроса.
Вы можете вызвать exception, если requests.get был неудачным. Такую конструкцию можно создать вызвав .raise_for_status() используя конструкцию try- except:
import requests
from requests.exceptions import HTTPError
for url in ['https://www.google.ru/', 'https://www.google.ru/invalid']:
try:
response = requests.get(url)
response.raise_for_status()
except HTTPError:
print(f'Возникла ошибка HTTP: {HTTPError}')
except Exception as err:
print(f'Возникла непредвиденная ошибка: {err}')
else:
print('Успех!')
# Вывод:
Успех!
Возникла ошибка HTTP: <class 'requests.exceptions.HTTPError'>
Заголовки ответов
Мы можем просматривать заголовки ответа сервера:
import requests
response = requests.get('https://www.google.ru/')
print(response.headers)
# Вывод:
{'Date': 'Sun, 27 Jun 2021 13:43:17 GMT', 'Expires': '-1', 'Cache-Control': 'private, max-age=0', 'Content-Type': 'text/html; charset=windows-1251', 'P3P': 'CP="This is not a P3P policy! See g.co/p3phelp for more info."', 'Content-Encoding': 'gzip', 'Server': 'gws', 'X-XSS-Protection': '0', 'X-Frame-Options': …
Cookies
Можно просмотреть файлы cookie, которые сервер отправляет вам обратно с помощью атрибута .cookies. Запросы также позволяют отправлять свои собственные cookie-файлы.
Чтобы добавить куки в запрос, Вы должны использовать dict, переданный в параметр cookie.
import requests
url = 'https://www.google.ru/'
headers = {'user-agent': 'your-own-user-agent/0.0.1'}
cookies = {'visit-month': 'February'}
response = requests.get(url, headers=headers, cookies=cookies)
print(response.request.headers)
# Вывод:
{'user-agent': 'your-own-user-agent/0.0.1', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Cookie': 'visit-month=February'}
Редиректы и история
По умолчанию модуль Requests выполняет редиректы для всех HTTP глаголов, кроме HEAD.
Существует возможность использовать параметр history объекта Response, чтобы отслеживать редиректы.
Например, GitHub перенаправляет все запросы HTTP на HTTPS:
import requests
response = requests.get('https://www.google.ru/')
print(response.url)
print(response.status_code)
print(response.history)
# Вывод:
https://www.google.ru/
200
[]
Тайм ауты
Так же легко можно управлять тем, сколько программа будет ждать возврат response. Время ожидания задаётся параметром timeout. Это очень важный параметр, так как, если его не использовать, написанный Вами скрипт может «зависнуть» в вечном ожидании ответа от сервера. Используем предыдущий код:
import requests
response = requests.get(‘https://www.google.ru/’, timeout=0.001)
print(response.url)
print(response.status_code)
print(response.history)
# Вывод:…
raise ConnectTimeout(e, request=request)
requests.exceptions.ConnectTimeout: HTTPSConnectionPool(host=’www.google.ru’, port=443): Max retries exceeded with url: / (Caused by ConnectTimeoutError(<urllib3.connection.HTTPSConnection object at 0x000001E331681C70>, ‘Connection to www.google.ru timed out. (connect timeout=0.001)’))
Модуль не ждёт полной загрузки ответа. Исключение возникает, если сервер не отвечает (хотя бы один байт) за указанное время.
Ошибки и исключения
Если возникнет непредвиденная ситуация – ошибка соединения, модуль Requests выбросит эксепшн ConnectionError.
response.raise_for_status() возвращает объект HTTPError, если в процессе произошла ошибка. Его применяют для отладки модуля и, поэтому, он является неотъемлемой частью запросов Python.
Если выйдет время запроса, вызывается исключение Timeout. Если слишком много перенаправлений, то появится исключение TooManyRedirects.