Библиотека Python Requests: документация на русском. Краткое руководство по библиотеке

В стандартной комплектации Python имеются модули, предназначенные для работы с HTTP-запросами. Тем не менее, они очень неудобны в использовании. Прежде всего, количество классов и функций поистине огромное, что приводит к тому, что нарушается сама идеология Python – простота и читабельность кода. А поскольку многие программисты решают использовать именно этот язык по этим причинам, то было принято решение разработать альтернативную библиотеку для работы с HTTP-запросами.

Быстрый старт в библиотеке Requests

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

Чтобы это сделать, необходимо воспользоваться командой.

$ python -m pip install requests

Или воспользоваться альтернативной командой для библиотеки PIP, которая установлена на вашем компьютере и нужном терминале. 

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

C:\Python34\Tools\Scripts\pip3.exe install numpy

Ну и, наконец, можно добавить саму библиотеку в директорию C:\Python34\Tools\Scripts\, но этот способ трудоемкий, и его стоит использовать, только если остальные не подходят.

Как создать запрос?

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

Перед тем, как использовать модуль Requests, его нужно импортировать. Для этого используется следующая команда.

import requests 

Давайте теперь попробуем обработать общий тайм-лайн GitHub с помощью нашей библиотеки.

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

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

Стандартный API рассматриваемой нами библиотеки подразумевает, что каждая разновидность HTTP-запросов очевидна. Приведем код, иллюстрирующий передачу POST-запроса.

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

Кроме GET и POST-запросов также есть дополнительные. Они также очень просто выполняются.

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’)  

Рассмотрим подробнее, что означает каждый из этих типов запросов.

  1. PUT-запрос. Это аналог POST-запроса, только имеет одно важное отличие от него. В то время, как последний создает, то PUT обновляет.
  2. DELETE-запрос. Нужен, чтобы удалить ресурс.
  3. HEAD-запрос. Необходим для получения заголовков ресурса. 
  4. OPTIONS-запрос. Нужен для описания параметров соединения с ресурсом.

Как передать параметры в URL?

Нередко приходится передавать параметры, используя URL-адрес. Если настройка осуществляется непосредственно в нем, то данные передаются по следующему образцу: httpbin.org/get?key=val. То есть, записывается метод запроса, потом пишется ключ, а затем – его значение.

Ничего не напоминает? Правильно, словарь Python, где информация хранится в таком же виде. Для этого применяется аргумент params. Например, нам требуется передать такие ключи ресурсу httpbin.org/get : key1=value1, key2=value2.

Чтобы это сделать, используется такой код.

payload = {‘key1’: ‘value1’, ‘key2’: ‘value2’}  

r = requests.get(‘https://httpbin.org/get’, params=payload)

print(r.url) 

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

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

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

Содержимое ответа (response)

Теперь поговорим о том, как прочитать, что сервер ответил нам. В качестве примера снова будем использовать GitHub.

>>> import requests

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

>>> r.text

‘[{«repository»:{«open_issues»:0,»url»:»https://github.com/…

Ответ сервера поступает в закодированном виде. Библиотека Requests будет автоматически производить декодирование. Как правило, если ответ пришел в кодировке Unicode, то не должно возникать никаких проблем.

Если кодировка другая, Request пытается определить, какая она, основываясь на заголовке HTTP-запроса. Можно также изменить кодировку, используя r.encoding.

>>> r.encoding

‘utf-8’

>>> r.encoding = ‘ISO-8859-1’

Последовательность действий, которая необходима в каждом конкретном случае, отличается. Так, в HTML и XML можно указать кодировку непосредственно в блоке заголовка.  В таком случае сначала необходимо определить кодировку с помощью r.content, а потом установить правильную кодировку с помощью r.encoding. Это даст возможность пользоваться правильной кодировкой документа.

Если появляется необходимость, то есть возможность использовать пользовательские кодировки. Для этого необходимо ее зарегистрировать в модуле codecs, а потом просто использовать ее имя в качестве значения r.encoding.

Бинарное содержимое ответа

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

from PIL import Image  

from io import BytesIO  

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

Содержимое ответа в JSON

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

>>> import requests

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

>>> r.json()

[{‘repository’: {‘open_issues’: 0, ‘url’: ‘https://github.com/…

Если же попытка декодирования оказалась неудачной, то функцией r.json() будет возвращена ошибка. Она зависит от кода, который прислал сервер. Например, при коде 204 будет возвращено следующее исключение: ValueError: No JSON object could be decoded.

Важно обратить внимание, что если r.json() вызывается без ошибок, это еще не означает, что сервер не вернул какое-то исключение. Так, некоторые из них могут возвращать именно JSON, если ответ неудачный. Для проверки запроса необходимо использовать такую команду r.raise_for_status()

Необработанное содержимое ответа

В некоторых случаях необходимо получить «сырой» ответ. Для этого используется метод r.raw. Эта возможность доступна лишь при условии, что в первом запросе было прописано stream=True. Затем уже можно выполнить следующие действия:

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

>>> r.raw

<urllib3.response.HTTPResponse object at 0x101194810>

>>> r.raw.read(10)

‘\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03’

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

with open(filename, ‘wb’) as fd:

    for chunk in r.iter_content(chunk_size=128):

        fd.write(chunk)

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

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

Пользовательские заголовки

Программист может добавлять собственные заголовки в HTTP-запрос. Для этого необходимо просто использовать соответствующий словарь в параметре запроса headers. Допустим, мы не вводили юзер-агент раньше. А чтобы его передать серверу, нужно использовать следующие строки.

url = ‘https://api.github.com/some/endpoint’  

headers = {‘user-agent’: ‘my-app/0.0.1’}  

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

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

  1. Заголовки авторизации, которые были установлены с помощью headers= переопределяются, если учетные сведения введены .netrc, переопределение которых осуществляется с использованием auth=.
  2. Их же удаление будет происходить при переадресации.
  3. Если обрабатываются заголовки авторизации с прокси-сервера, то их переопределение будет зависеть от тех данных, которые записаны в URL.
  4. Переопределение Content-Length происходит при определении длины контента.

Более того, запросы вообще не корректируют свои действия, учитывая заголовки.

Более сложные POST-запросы

Хорошо, а что делать, если хочется отправить form-encoded точно так же, как в веб-форме? Чтобы это сделать, требуется попросту отправить подходящий словарь в качестве параметра data. В данной ситуации этот словарь автоматом будет закодирован в виде HTML-формы при выполнении запроса.

>>> payload = {‘key1’: ‘value1’, ‘key2’: ‘value2’}

>>> r = requests.post(«https://httpbin.org/post», data=payload)

>>> print(r.text)

{

  …

  «form»: {

    «key2»: «value2»,

    «key1»: «value1»

  },

  …

}

С помощью аргумента data можно осуществлять передачу сразу нескольких значений для каждого из ключей. На практике это реализуется с помощью формата tuple или же в форме словаря, в котором в качестве значений ключа используются списки (то есть, фигурные скобки). В частности, это пригодится, если в форме есть больше одного элемента, завязанных на том же самом ключе.

>>> 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

Но ситуации бывают разные. Например, иногда требуется отправить сведения, которые не были закодированы с использованием form-encoded. Если же использовать строку вместо словаря в запросе, то отправка данных осуществляется без каких-либо изменений.

Вместо кодирования словаря можно также выполнить его прямую передачу, применяя параметр json, после чего кодировка осуществится автоматически.

Если выполняется передача data или files, то тогда параметр json пропускается.

Также важно учесть, что если использовать json в запросе, то заголовок изменяется на application/json.

POST отправка Multipart-Encoded файла

Если кодирование многостраничное, то с помощью запросов можно сделать загрузку файлов проще. Возможны различные действия с Multipart-Encoded файлами:

  1. Загрузка.
  2. Изменение имени файла, типа контента, заголовков.
  3. Отправка строк, которые используются в виде файлов.

Приведем пример, как осуществляется POST-отправка файла.

>>> url = ‘https://httpbin.org/post’

>>> files = {‘file’: open(‘report.xls’, ‘rb’)}

>>> r = requests.post(url, files=files)

>>> r.text

{

  …

  «files»: {

    «file»: «<censored…binary…data>»

  },

  …

}

В некоторых случаях придется отправлять запросы потоком. К сожалению, такая функция не поддерживается стандартной библиотекой requests, тем не менее можно воспользоваться специальным пакетом, который поддерживает эту возможность. Чтобы получить более детальную информацию, необходимо воспользоваться официальной документацией requests-toolbelt.

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

Коды состояния ответа

Помните, мы ранее описывали, что не всегда, если сервер выдает ошибку, она возвращается в самом Python? Еще один способ проверить, нет ли ошибок, а также проверить в целом состояние ответа – это воспользоваться методом r.status_code.

Если запрос оказался неудачным, то есть, имеет код, начинающийся с 4 или 5, то можно его обработать с помощью метода raise_for_status() объекта класса Response.

>>> 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

Заголовки ответов

С помощью словаря Python мы имеем возможность просматривать заголовки ответов сервера. Для этого используется метод headers. Он возвращает словарь с ключами и значениями, которые передаются сервером. 

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

Cookies

Библиотека Requests позволяет получить доступ к cookies. Приведем пример кода, где это делается.

>>> url = ‘https://example.com/some/cookie/setting/url’

>>> r = requests.get(url)

>>> r.cookies[‘example_cookie_name’]

‘example_cookie_value’

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

>>> url = ‘https://httpbin.org/cookies’

>>> cookies = dict(cookies_are=’working’)

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

>>> r.text

‘{«cookies»: {«cookies_are»: «working»}}’

Редиректы и история

По стандартным параметрам Requests выполняет редиректы для всех HTTP-запросов, за исключением HEAD. Чтобы отслеживать перенаправления, используется специальное свойство history объекта Response.

Тайм-ауты

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

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

Traceback (most recent call last):

  File «», line 1, in 

requests.exceptions.Timeout: HTTPConnectionPool(host=’github.com’, port=80): Request timed out. (timeout=0.001)

Возможные ошибки и исключения

Возможны следующие ошибки в процессе работы с запросами:

  1. ConnectionError. Означает наличие неполадок в сети. Например, если внезапно отключается интернет или отказывает DNS-сервер. 
  2. HTTPError. Если возвращается код ошибки при использовании метода raise_for_status().
  3. TooManyRedirects – означает слишком большое количество редиректов.
ОфисГуру
Adblock
detector