Библиотека Requests Python

Для Python написано много хороших и полезных библиотек. Requests — одна из них. Она предназначена для отправки HTTP-запросов. Это сторонняя альтернатива стандартным urllib, urllib2 и urllib3, которые могут быть запутанными и часто требуют совместного использования.

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

Содержание

Что такое библиотека Python Requests?

Хотите скачать книги по Python в 2 клика? Тогда вам в наш телеграм канал PythonBooks 

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

Интуитивно понятный API позволяет легко отправлять HTTP-запросы, поддерживая при этом множество HTTP-методов, включая GET, PUT, DELETE, HEAD, OPTIONS и PATCH.

Философия Requests

Разработчики библиотеки Requests стремились сделать ее максимально простой в изучении и использовании. Стандартные HTTP-библиотеки Python, напротив, сложны и часто требуют значительно больше операторов для выполнения одной и той же задачи. Давайте рассмотрим примеры применения Urllib3 и Requests:

Urllib3:

import urllib3

http = urllib3.PoolManager()
gh_url = 'https://api.github.com'
headers = urllib3.util.make_headers(user_agent= 'my-agent/1.0.1', basic_auth='abc:xyz')
requ = http.request('GET', gh_url, headers=headers)
print (requ.headers)
print(requ.data)
# ------# 200# 'application/json'

Requests:

import requests
r = requests.get('https://api.github.com', auth=('user', 'pass'))
print r.status_codeprint r.headers['content-type']
# ------# 200# 'application/json'

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

Как видно, Requests заметно эффективнее любой стандартной библиотеки Python, и это не случайно. При ее разработке учитывались и учитываются несколько идиом из PEP 20 (The Zen of Python):

  1. Красивое лучше уродливого.
  2. Явное лучше неявного.
  3. Простое лучше сложного.
  4. Сложное лучше, чем запутанное.
  5. Читабельность имеет значение.

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

Как установить Requests в Python

Requests не является частью стандартной библиотеки Python, поэтому ее необходимо загрузить и установить. Установка Requests проста и выполняется через терминал.

$ pip install requests

Мы рекомендуем использовать терминал, поставляемый в среде разработки (например, PyCharm), так как это обеспечит беспрепятственную установку библиотеки.

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

import requests

GET-запросы

Из всех возможных типов HTTP-запросов наиболее часто используется GET. Этот запрос, как видно из названия, представляет собой возможность получить данные из указанного источника (обычно это сайт).

Чтобы отправить GET-запрос, воспользуйтесь методом requests.get() и передайте в него URL-адрес назначения. Например:

import requests
requests.get('http://httpbin.org/')

Наш пример базового запроса в Python возвращает ответ с кодом 200 <Response [200]>, показывающий, что запрос был выполнен успешно. Код ответа можно получить, обратившись к свойству ответа status_code. Существует множество других кодов, но наиболее часто встречаются следующие:

  • 200 — ‘OK’
  • 400 — ‘Bad request’ отправляется, когда сервер не может понять запрос, отправленный клиентом. Как правило, это свидетельствует о неправильном синтаксисе запроса, некорректном формировании сообщения запроса и т.д.
  • 401 — ‘Unauthorized’ отправляется в том случае, если для выполнения запроса необходимо предоставить учетные данные.
  • 403 — ‘Forbidden’ означает, что сервер понял запрос, но не будет его выполнять. В тех случаях, когда были предоставлены учетные данные, 403 означает, что данная учетная запись не имеет достаточных прав для просмотра содержимого.
  • 404 — ‘Not found’ означает, что сервер не нашел содержимого, соответствующего Request-URI. Иногда 404 используется для маскировки ответов 403, когда сервер не хочет раскрывать причины отказа в запросе.
  • 429 — этот код ошибки является более сложным, поскольку означает, что клиент превысил установленные сервером лимиты на запросы. По сути, сервер получает слишком много запросов от клиента за определенный промежуток времени и временно блокирует дальнейшие запросы от этого клиента. Пример обработки такой ошибки может выглядеть следующим образом:
import requests
import time

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

if response.status_code == 429:
    retry_after = int(response.headers.get('Retry-After', 1))
    print(f"Rate limit exceeded. Waiting {retry_after} seconds before retrying...")
    time.sleep(retry_after)
    response = requests.get('https://example.com/api')
окно ошибки 404
404 означает, что запрашиваемая страница не найдена на сервере сайта

Параметры GET-запросов

При необходимости GET-запросы могут отправляться с определенными параметрами. Параметры передаются по той же логике, что и при построении URL вручную. Они ставятся после вопросительного знака, добавляемого к исходному URL, а пары разделяются знаком амперсанда (&):

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

Теперь наш URL выглядит так:

https://httpbin.org/get?key2=value2&key1=value1

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

Чтение ответов

Для того чтобы просмотреть объект ответа (response) Requests, отправленный с помощью GET-запроса, мы должны создать переменную. В целях простоты давайте назовем ее response:

response = requests.get('http://httpbin.org/')

В Requests значение таймаута по умолчанию установлено на none. Это означает, что если мы не будем получать ответ от сервера, то наше приложение зависнет на неопределенное время.

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

print(response.status_code)

Пока вывод будет идентичен полученному ранее <Response [200]> . Обратите внимание, что коды статуса имеют булевы значения (200 до 399 — True, 400 и выше — False).

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

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

print(response.text)

Requests автоматически пытается сделать обоснованное предположение о кодировке на основе HTTP-заголовков, поэтому явное указание кодировки не требуется. В редких случаях может потребоваться изменение кодировки. Это можно сделать, передав значение в response.encoding. Указанное нами значение будет использоваться при каждом вызове.

Ответы также можно декодировать в формат JSON. Однако HTTPbin не отправляет запрос, который можно было бы декодировать в JSON. Попытка сделать это вызовет исключение.

В качестве пояснительного примера давайте сделаем запрос к GitHub API:

response = requests.get('http://api.github.com')
print(response.json())

Использование .json() возвращает объект словаря (dictionary), к которому дальше можно обратиться и осуществлять поиск по нему.

Использование заголовков запросов

Заголовки ответа (response headers) — это еще одна важная часть запроса. Хотя они не содержат контента исходного сообщения, в них есть много важной информации об ответе, такой как информация о сервере, дата, кодировка и т.д. Эти данные могут быть получены из исходного ответа следующим образом:

print(response.headers)

Подобно вызову .json(), заголовки создают объект типа словаря (dictionary), к которому можно обратиться. Указание ключей позволит вывести определенную часть ответа, например:

print(response.headers['Date'])

Теперь наш код будет выводить дату, хранящуюся в заголовке ответа. Значения считаются нечувствительными к регистру, поэтому запросы будут выводить один и тот же результат независимо от того, был ли параметр передан как ‘date’ или ‘Date’.

Вы также можете передавать пользовательские заголовки запросов. Здесь снова используются объекты типа Dictionary, но на этот раз их необходимо создать. Передача заголовков осуществляется аналогично параметрам.

Чтобы проверить, успешно ли был отправлен заголовок нашего запроса, необходимо выполнить вызов response.request.headers:

import requests

headers = {'user-agent': 'my-agent/1.0.1'}
response = requests.get('http://httpbin.org/', headers=headers)
print(response.request.headers)

В результате выполнения нашего кода в окне отладчика должен появиться заголовок запроса с указанием агента пользователя 'my-agent/1.0.1'.

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

POST-запросы

Отправка POST-запроса в Python является вторым наиболее часто используемым методом HTTP. Этот тип запроса используется для создания ресурса на сервере с указанными данными. Отправка POST-запроса почти так же проста, как отправка GET-запроса:

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

Все методы HTTP (исключение составляет HEAD) возвращают тело ответа, которое можно прочитать. Ответы на POST-запросы могут быть получены так же, как и ответы на GET-запросы (или любые другие):

print(response.text)

Ответы, вполне очевидно, связаны с типами сделанных запросов. Например, ответ на POST-запрос содержит информацию о данных, отправленных на сервер.

В большинстве случаев указание данных в POST-запросе может быть недостаточным. Библиотека Requests принимает аргументы из объектов словаря, которые могут быть использованы для отправки более сложных данных:

payload = {'key1': 'value1', 'key2': 'value2'}
response = requests.post('https://httpbin.org/post', data = payload)

Наш новый запрос отправит объект полезной нагрузки на целевой сервер. Порой может потребоваться отправка POST-запросов в формате JSON. В запросах есть дополнительная функция, которая автоматически преобразует данные POST-запроса в JSON.

import requests

payload = {'key1': 'value1', 'key2': 'value2'}
response = requests.post('https://httpbin.org/post', json = payload)
print(response.json())

В качестве альтернативы можно использовать библиотеку json для преобразования словарей в объекты JSON.

От редакции Pythonist: об использовании оson читайте в статье «Формат данных JSON в Python».

Для изменения типа объекта потребуется новый импорт:

import json
import requests

payload = {
    'key1': 'value1',
    'key2': 'value2'}
jsonData = json.dumps(payload)
response = requests.post('https://httpbin.org/post', data = jsonData)
print(response.json())

Обратите внимание, что аргумент «json» будет перезаписан, если используется аргумент «data» или «files». Библиотека Requests использует только один из этих трех аргументов в одном POST-запросе.

Другие методы HTTP

POST и GET — два наиболее распространенных метода, используемых обычным пользователем. Например, пользователи scraper API используют только эти два HTTP-метода для отправки запросов (POST) и получения данных (GET). Однако существует гораздо больше способов взаимодействия с серверами по протоколу HTTP.

PUT

Запрос PUT заменяет все текущие представления целевого ресурса представленным содержимым.

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

Отправка PUT-запроса аналогична отправке POST-запроса, но с использованием метода put():

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

DELETE

Запрос DELETE удаляет все существующие представления целевого ресурса, заданного URL.

Метод delete() посылает запрос на указанный URL и предназначен для удаления указанного ресурса. Отправка запроса DELETE аналогична отправке любого другого HTTP-запроса, синтаксис следующий:

requests.delete(url, params={key: value}, args)

Выполним примерный запрос DELETE, удаляющий ресурс «delete»:

import requests
  
# Making a DELETE request
response = requests.delete('https://httpbin.org/delete')

Мы можем вывести код ответа, чтобы проверить полученный ответ:

print(response.status_code)

HEAD

Запрос HEAD подобен GET, но только передает статус и заголовочную часть.

Метод head() запрашивает данные у веб-сервера. При этом возвращается только информация о веб-сервере, а не само содержимое. Это делает его более быстрым, чем запрос GET.

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

Базовый синтаксис запроса HEAD:

requests.head(url, **kwargs)

OPTIONS

Запрос OPTIONS задает параметры связи с целевым ресурсом.

Метод options() извлекает объект ответа, содержащий все данные и свойства, такие как содержимое ответа, заголовки, кодировка, cookies и т.д.

Базовый синтаксис запроса OPTIONS:

response = requests.options(url)

PATCH

Запрос PATCH — применение изменений к указанному ресурсу. Этот запрос должен содержать только изменения ресурса, а не весь ресурс.

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

Синтаксис запроса PATCH выглядит следующим образом:

requests.patch(url, params={key: value}, args)

Все перечисленные выше методы HTTP редко используются за пределами администрирования сервера, веб-разработки, тестирования и отладки. Обычный пользователь Интернета практически ни на одном сайте не имеет права выполнять такие действия, как DELETE или PUT.

Конечно, наиболее распространенным является метод GET, который позволяет разработчикам получать данные из API с помощью пакета requests.

Воспользуемся методом requests.get() для отправки HTTP GET-запроса на сайт http://httpbin.org/ip:

response = requests.get("http://httpbin.org/ip")

Теперь мы можем использовать этот объект ответа и такие методы, как status_code, content, text и json(), для получения дополнительной информации.

Что такое аутентифицированный запрос?

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

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

Отправка данных с помощью аутентифицированных запросов

Для отправки данных с помощью аутентифицированных запросов сначала необходимо получить учетные данные для аутентификации. К распространенным методам аутентификации относятся, например, ключи API и маркеры OAuth.

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

Пример отправки POST-запроса с полезной нагрузкой в формате JSON и базовой аутентификацией:

import requests

url = 'https://example.com/api/data'
payload = {'key1': 'value1', 'key2': 'value2'}
auth = ('username', 'password')
headers = {'Content-Type': 'application/json'}

response = requests.post(url, json=payload, auth=auth, headers=headers)

if response.status_code == 200:
    print('Data sent successfully')
else:
    print('Error sending data:', response.text)

В приведенном примере мы сначала определяем URL-адрес, на который будет отправлен запрос, и данные, которые мы хотим отправить в формате JSON. Мы также указываем учетные данные для аутентификации, используя метод базовой аутентификации, где пишем имя пользователя и пароль. Еще мы устанавливаем заголовок Content-Type, чтобы указать, что мы отправляем данные в формате JSON.

Затем мы используем метод requests.post() для отправки запроса с заголовками аутентификации и информацией в формате JSON. Если запрос выполняется успешно (т.е. мы получаем код состояния 200), то выводим сообщение об успехе. В противном случае выводится сообщение об ошибке с текстом ответа.

Получение данных с помощью аутентифицированных запросов

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

Приведем пример получения данных с помощью аутентификационных запросов с использованием метода GET и ключа API:

import requests

url = 'https://example.com/api/data'
api_key = 'your-api-key'
headers = {'Authorization': f'Bearer {api_key}'}

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

if response.status_code == 200:
    data = response.json()
    print('Data retrieved successfully:', data)
else:
    print('Error retrieving data:', response.text)

В приведенном примере мы определяем URL-адрес, по которому хотим получить данные, и указываем ключ API с помощью заголовка Authorization с типом токена Bearer. Затем мы используем метод requests.get() для отправки запроса с соответствующими заголовками аутентификации.

В случае успешного выполнения запроса мы выводим полученные данные. В противном случае выводится сообщение об ошибке с текстом ответа.

Проверка сертификата SSL

Защита обмена данными между несколькими системами является критически важной для обеспечения конфиденциальности и целостности данных в современных условиях. Использование сертификатов SSL/TLS, обеспечивающих шифрованное соединение между системами, является одним из способов обеспечения безопасности связи.

SSL Verification — это процесс, который проверяет подлинность сервера, с которым мы соединяемся, и действительность сертификата SSL/TLS, представленного сервером. SSL Verification необходима для предотвращения атак типа «man-in-the-middle», при которых злоумышленник перехватывает связь между двумя сторонами и изменяет передаваемые данные.

Пакет requests в Python предоставляет простой интерфейс для выполнения HTTP-запросов. Для обеспечения безопасного взаимодействия библиотека по умолчанию выполняет SSL-проверку. Однако в некоторых случаях, например, при работе с самоподписанными сертификатами или тестировании на локальном сервере, может потребоваться отключить проверку SSL-сертификата.

Для отключения проверки SSL в библиотеке Requests установите аргумент verify в значение False. Приведем пример отправки GET-запроса на сервер без использования SSL:

import requests

url = 'https://example.com/api/data'
response = requests.get(url, verify=False)

if response.status_code == 200:
    print('Data retrieved successfully')
else:
    print('Error retrieving data:', response.text)

Для обеспечения безопасного соединения библиотека Requests по умолчанию выполняет проверку SSL. Если SSL/TLS-сертификат сервера недействителен, библиотека выбросит исключение CertificateError. Однако иногда нам необходимо предоставить свой сертификат SSL/TLS или использовать специальный CA-пакет.

Чтобы включить проверку SSL с помощью пользовательского пакета CA, используйте аргумент verify, указывая путь к файлу пакета CA.

Пример использования пользовательского пакета CA для отправки GET-запроса на сервер с включенной SSL-проверкой:

import requests

url = 'https://example.com/api/data'
ca_bundle = '/path/to/ca/bundle.crt'
response = requests.get(url, verify=ca_bundle)

if response.status_code == 200:
    print('Data retrieved successfully')
else:
    print('Error retrieving data:', response.text)

Bearer Token 

Bearer токены часто используются в API для аутентификации и авторизации. Чтобы использовать его в библиотеке в нашем коде, мы можем включить его в качестве заголовка в наши HTTP-запросы.

Приведем пример использования токена для отправки GET-запроса к API:

import requests

url = 'https://example.com/api/data'
token = 'Bearer my_access_token'
headers = {'Authorization': token}
response = requests.get(url, headers=headers)

if response.status_code == 200:
    data = response.json()
    print('Data retrieved successfully')
else:
    print('Error retrieving data:', response.text)

В предыдущем примере мы определяем URL запроса, с которого хотим получить данные, и указываем наш токен в качестве заголовка в поле Authorization запросов с помощью аргумента headers.

Если запрос проходит успешно (выдается код состояния 200), мы используем функцию response.json() для преобразования JSON-данных, возвращаемых API, в объект Python. В противном случае мы выводим сообщение об ошибке и содержимое ответа.

Заключение

Библиотека Python Requests — это одновременно невероятно мощный и простой в использовании инструмент, которым можно пользоваться для отправки HTTP-запросов. Понимания основ работы с ним часто бывает достаточно для создания простых приложений или скриптов.

Часто задаваемые вопросы

Библиотека Requests доступна в Python 3 «из коробки»?

К сожалению, нет. Если вы хотите ее использовать, вам придется установить ее отдельно.

Какова альтернатива легкой версии Requests в Python?

Хорошей альтернативой может стать HTTPX. Это быстрая и всеобъемлющая клиентская библиотека HTTP, специально разработанная для Python 3 и мобильных платформ. Кроме того, она поддерживает HTTP/1.1 и HTTP/2, имеет простой API и предоставляет такие полезные возможности, как поддержка async и пулов соединений.

В чем разница между Requests и BeautifulSoup?

Хотя и Requests, и BeautifulSoup являются библиотеками Python, используемыми для веб-скрапинга, они служат несколько разным целям.

Например, Requests позволяет отправлять HTTP/HTTPS-запросы на сайт и получать ответ, в отличие от BeautifulSoup, которая позволяет извлекать данные из HTML- и XML-документов.

По сути, Requests отправляет запросы на сайт, чтобы получить HTML-содержимое, а BeautifulSoup анализирует HTML-содержимое и извлекает необходимые данные.

Requests — это библиотека или пакет?

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

Перевод статьи «Python Requests Library: 2023 Guide».