Библиотека запросов Python (руководство)

Оглавление

Смотрите сейчас, к этому уроку прилагается соответствующий видеокурс, созданный командой Real Python. Посмотрите его вместе с письменным руководством, чтобы углубить свое понимание: Создание HTTP-запросов с помощью Python

Библиотека Запросов - это готовый пакет для выполнения HTTP-запросов на Python. Он позволяет абстрагироваться от сложностей выполнения запросов с помощью интуитивно понятного API. Хотя он и не является частью стандартной библиотеки Python, стоит рассмотреть запросы для выполнения HTTP-действий, таких как GET, POST и других.

К концу этого урока вы поймете, что:

  • Requests не является встроенным модулем Python - это сторонняя библиотека, которую необходимо установить отдельно.
  • Вы отправляете запрос GET на Python, используя requests.get() с нужным URL-адресом.
  • Чтобы добавить заголовки к запросам, передайте словарь заголовков параметру headers в вашем запросе.
  • Чтобы отправить данные POST, используйте параметр data для данных, закодированных в форме, или параметр json для данных JSON.
  • response.text выдает строку, представляющую содержимое ответа, в то время как response.content предоставляет необработанные байты.

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

Если вы хотите изучить примеры кода, которые вы увидите в этом руководстве, вы можете скачать их здесь:

Получите свой код: Нажмите здесь, чтобы загрузить бесплатный пример кода, который показывает, как использовать библиотеку запросов Python.

<отметить класс="marker-highlight"> Пройдите тест: Проверьте свои знания с помощью нашего интерактивного теста ”Библиотека запросов Python". По завершении вы получите оценку, которая поможет вам отслеживать прогресс в обучении:

<время работы/> Python’s Requests Library (Guide)

Интерактивная викторина

Библиотека запросов Python

Проверьте свое понимание библиотеки запросов Python для выполнения HTTP-запросов и взаимодействия с веб-службами.

Начало работы с Библиотекой Запросов Python

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

Примечание: Если вы хотите выполнять HTTP-запросы только с помощью стандартной библиотеки Python, то Python urllib.request - это хороший выбор для вас.

Поскольку Requests - это сторонняя библиотека, вам необходимо установить ее, прежде чем использовать в своем коде. Рекомендуется устанавливать внешние пакеты в виртуальную среду, но вы можете установить requests в свою глобальную среду, если планируете использовать ее в нескольких проектах.

Независимо от того, работаете вы в виртуальной среде или нет, вам необходимо установить requests:

$ python -m pip install requests


Как только pip завершит установку requests, вы сможете использовать его в своем приложении. Импорт requests выглядит следующим образом:

import requests


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

Сделать запрос на получение

HTTP-методы, такие как GET и POST, указывают действие, которое вы хотите выполнить при отправке HTTP-запроса. В дополнение к GET и POST существует несколько других распространенных методов, которые вы будете использовать позже в этом руководстве.

Одним из наиболее часто используемых HTTP-методов является GET, который извлекает данные из указанного ресурса. Чтобы отправить запрос GET с помощью запросов, вы можете вызвать requests.get().

Чтобы попробовать это, вы можете сделать GET запрос к REST API GitHub, вызвав get() со следующим URL-адресом:

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


Поздравляем! Вы отправили свой первый запрос. Теперь давайте немного углубимся в ответ на этот запрос.

Проверьте ответ

A Response - это объект, содержащий результаты вашего запроса. Попробуйте выполнить тот же запрос еще раз, но на этот раз сохраните возвращаемое значение в переменной, чтобы вы могли более подробно ознакомиться с ее атрибутами и поведением:

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


В этом примере вы получили возвращаемое значение requests.get(). Это экземпляр Response, и вы сохранили его в переменной с именем response. Теперь вы можете использовать response, чтобы просмотреть больше информации о результатах вашего запроса GET.

Работа с Кодами состояния

Первая часть информации, которую вы можете почерпнуть из 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.

Запросы - это еще один шаг в упрощении этого процесса для вас. Если вы используете Response экземпляр в логическом контексте, таком как условный оператор, то он будет равен True когда код состояния меньше 400, и False в противном случае.

Это означает, что вы можете изменить последний пример, переписав оператор if:

if response:
    print("Success!")
else:
    raise Exception(f"Non-success status code: {response.status_code}")


В приведенном выше фрагменте кода вы неявно проверяете, находится ли .status_code из response между 200 и 399. Если это не так, то вы создаете исключение с сообщением об ошибке, которое содержит код состояния "сбой", заключенный в f-струна.

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

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

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

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

Предположим, вы не хотите проверять код состояния ответа в инструкции if. Вместо этого вы хотите использовать встроенные возможности Request для создания исключения, если запрос не был выполнен. Вы можете сделать это с помощью .raise_for_status():

raise_error.py
import requests
from requests.exceptions import HTTPError

URLS = ["https://api.github.com", "https://api.github.com/invalid"]

for url in URLS:
    try:
        response = requests.get(url)
        response.raise_for_status()
    except HTTPError as http_err:
        print(f"HTTP error occurred: {http_err}")
    except Exception as err:
        print(f"Other error occurred: {err}")
    else:
        print("Success!")

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

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

Доступ к содержимому ответа

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

Чтобы просмотреть содержимое ответа в bytes, вы используете .content:

>>> import requests

>>> response = requests.get("https://api.github.com")
>>> response.content
b'{"current_user_url":"https://api.github.com/user", ...}'

>>> type(response.content)
<class 'bytes'>


Хотя .content предоставляет вам доступ к необработанным байтам полезной нагрузки ответа, вам часто захочется преобразовать их в строку, используя кодировка символов, например UTF-8. response сделает это за вас, когда вы получите доступ к .text:

>>> response.text
'{"current_user_url":"https://api.github.com/user", ...}'

>>> type(response.text)
<class 'str'>


Поскольку для декодирования bytes в str требуется схема кодирования, Запросы будут пытаться угадать кодировку на основе заголовков ответа , если вы ее не укажете. Вы можете указать явную кодировку, установив .encoding перед доступом .text:

>>> response.encoding = "utf-8"  # Optional: Requests infers this.
>>> response.text
'{"current_user_url":"https://api.github.com/user", ...}'


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

>>> response.json()
{'current_user_url': 'https://api.github.com/user', ...}

>>> type(response.json())
<class 'dict'>


Тип возвращаемого значения .json() - это словарь, поэтому вы можете получить доступ к значениям в объекте по ключу:

>>> response_dict = response.json()
>>> response_dict["emojis_url"]
'https://api.github.com/emojis'


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

Просмотр заголовков ответов

Заголовки ответа могут предоставить вам полезную информацию, такую как тип содержимого полезной нагрузки ответа и продолжительность кэширования ответа. Чтобы просмотреть эти заголовки, перейдите к .headers:

>>> import requests

>>> response = requests.get("https://api.github.com")
>>> response.headers
{'Server': 'github.com',
...
'X-GitHub-Request-Id': 'AE83:3F40:2151C46:438A840:65C38178'}


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

>>> response.headers["Content-Type"]
'application/json; charset=utf-8'


В этом словарном объекте headers есть что-то особенное. Спецификация HTTP определяет заголовки как нечувствительные к регистру, что означает, что вы можете обращаться к ним, не беспокоясь об их заглавных буквах:

>>> response.headers["content-type"]
'application/json; charset=utf-8'


Независимо от того, используете ли вы ключ "content-type" или "Content-Type", вы получите одно и то же значение.

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

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

Добавить параметры строки запроса

Одним из распространенных способов настройки запроса GET является передача значений через строку запроса параметров в URL-адресе. Чтобы сделать это с помощью get(), вы передаете данные в params. Например, вы можете воспользоваться поиском по репозиторию на GitHub API для поиска популярных репозиториев Python:

search_popular_repos.py
import requests

response = requests.get(
    "https://api.github.com/search/repositories",
    params={"q": "language:python", "sort": "stars", "order": "desc"},
)

json_response = response.json()
popular_repositories = json_response["items"]
for repo in popular_repositories[:3]:
    print(f"Name: {repo['name']}")
    print(f"Description: {repo['description']}")
    print(f"Stars: {repo['stargazers_count']}\n")

Передавая словарь в params параметр get(), вы можете изменять результаты, получаемые из API поиска.

Вы можете передать params в get() либо в виде словаря, как вы только что сделали, либо в виде списка кортежей:

>>> import requests

>>> requests.get(
...     "https://api.github.com/search/repositories",
...     [("q", "language:python"), ("sort", "stars"), ("order", "desc")],
... )
<Response [200]>


Вы даже можете передать значения в виде bytes:

>>> requests.get(
...     "https://api.github.com/search/repositories",
...     params=b"q=language:python&sort=stars&order=desc",
... )
<Response [200]>


Строки запроса полезны для параметризации GET запросов. Еще один способ настроить запросы - добавить или изменить заголовки, которые вы отправляете.

Настройка заголовков запросов

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

text_matches.py
import requests

response = requests.get(
    "https://api.github.com/search/repositories",
    params={"q": '"real python"'},
    headers={"Accept": "application/vnd.github.text-match+json"},
)

json_response = response.json()
first_repository = json_response["items"][0]
print(first_repository["text_matches"][0]["matches"])

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

Когда вы запустите этот скрипт на Python, вы получите результат, аналогичный показанному ниже:

$ python text_matches.py
[{'text': 'Real Python', 'indices': [23, 34]}]


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

Используйте другие HTTP-методы

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

Примечание: Чтобы опробовать эти HTTP-методы, вам необходимо отправить запросы по адресу httpbin.org. Сервис httpbin - отличный ресурс, созданный первоначальным автором запросов, Кеннетом Рейтцем. Сервис принимает тестовые запросы и отвечает данными о запросах.

Вы заметите, что Requests предоставляет интуитивно понятный интерфейс для всех распространенных HTTP-методов:

>>> import requests

>>> requests.get("https://httpbin.org/get")
<Response [200]>
>>> requests.post("https://httpbin.org/post", data={"key": "value"})
<Response [200]>
>>> requests.put("https://httpbin.org/put", data={"key": "value"})
<Response [200]>
>>> requests.delete("https://httpbin.org/delete")
<Response [200]>
>>> requests.head("https://httpbin.org/get")
<Response [200]>
>>> requests.patch("https://httpbin.org/patch", data={"key": "value"})
<Response [200]>
>>> requests.options("https://httpbin.org/get")
<Response [200]>


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

Все эти функции являются высокоуровневыми сокращениями для requests.request(),, которые принимают имя метода в качестве первого аргумента:

>>> requests.request("GET", "https://httpbin.org/get")
<Response [200]>


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

>>> 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 и узнаете, чем они отличаются от других типов запросов.

Отправить данные запроса

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

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

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

>>> import requests

>>> 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, запросы сериализуют ваши данные и добавляют правильный заголовок Content-Type для вас.

Как вы узнали ранее, служба httpbin принимает тестовые запросы и отвечает данными о запросах. Например, вы можете использовать ее для проверки базового запроса 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'


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

Проверьте подготовленный запрос

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

Вы можете просмотреть объект PreparedRequest, перейдя к .request объекту Response:

>>> import requests

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

>>> response.request
<PreparedRequest [POST]>

>>> response.request.headers["Content-Type"]
'application/json'

>>> response.request.url
'https://httpbin.org/post'

>>> response.request.body
b'{"key": "value"}'


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

До сих пор вы делали множество различных запросов, но у всех них была одна общая черта: это были неаутентифицированные запросы к общедоступным API. Многие службы, с которыми вы столкнетесь, захотят, чтобы вы каким-либо образом прошли аутентификацию.

Использовать аутентификацию

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

>>> import requests

>>> response = requests.get(
...     "https://httpbin.org/basic-auth/user/passwd",
...     auth=("user", "passwd")
... )

>>> response.status_code
200
>>> response.request.headers["Authorization"]
'Basic dXNlcjpwYXNzd2Q='


Запрос выполняется успешно, если учетные данные, которые вы передаете в кортеже auth, действительны.

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

Вы можете задаться вопросом, откуда берется строка Basic dXNlcjpwYXNzd2Q=, которая запрашивает значение в качестве значения для вашего заголовка Authorization. Короче говоря, это строка имени пользователя и пароля в кодировке Base64 с префиксом "Basic ":

  1. Во-первых, запросы объединяют имя пользователя и пароль, которые вы предоставляете, вставляя между ними двоеточие. Итак, для имени пользователя "user" и пароля "passwd" это становится "user:passwd".

  2. Затем Requests кодирует эту строку в Base64, используя base64.b64encode(). Кодировка преобразует строку "user:passwd" в "dXNlcjpwYXNzd2Q=".

  3. Наконец, Requests добавляет "Basic " перед этой строкой Base64.

Таким образом, конечное значение для заголовка Authorization становится Basic dXNlcjpwYXNzd2Q= в примере, показанном выше.

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

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

>>> from requests.auth import HTTPBasicAuth
>>> requests.get(
...     "https://httpbin.org/basic-auth/user/passwd",
...     auth=HTTPBasicAuth("user", "passwd")
... )
<Response [200]>


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

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

Если вы попытаетесь отправить запрос без учетных данных, то увидите, что код состояния равен 401 Unauthorized:

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


Если вы не укажете учетные данные для проверки подлинности при доступе к службе, которая их требует, в качестве ответа вы получите код ошибки HTTP.

Чтобы отправить запрос к аутентифицированному пользовательскому API GitHub, вам сначала необходимо сгенерировать персональный токен доступа с параметром read:user scope. Затем вы можете передать этот токен в качестве второго элемента в кортеже в get():

>>> import requests

>>> token = "<YOUR_GITHUB_PA_TOKEN>"
>>> response = requests.get(
...     "https://api.github.com/user",
...     auth=("", token)
... )
>>> response.status_code
200


Как вы узнали ранее, этот подход передает учетные данные в HTTPBasicAuth, который ожидает ввода имени пользователя и пароля, и отправляет учетные данные в виде строки в кодировке Base64 с префиксом "Basic ":

>>> response.request.headers["Authorization"]
'Basic OmdocF92dkd...WpremM0SGRuUGY='


Этот метод работает, но это неправильный способ аутентификации с помощью Bearer токена — и использовать пустую строку для ввода лишнего имени пользователя неудобно.

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

custom_token_auth.py
from requests.auth import AuthBase

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

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

    def __call__(self, request):
        """Attach an API token to the Authorization header."""
        request.headers["Authorization"] = f"Bearer {self.token}"
        return request

Здесь ваш пользовательский механизм TokenAuth получает токен, затем включает этот токен в Authorization заголовок вашего запроса, также устанавливая рекомендуемый префикс "Bearer " для строки.

Теперь вы можете использовать эту пользовательскую аутентификацию с помощью токена для обращения к аутентифицированному пользовательскому API GitHub:

>>> import requests
>>> from custom_token_auth import TokenAuth

>>> token = "<YOUR_GITHUB_PA_TOKEN>"
>>> response = requests.get(
...     "https://api.github.com/user",
...     auth=TokenAuth(token)
... )

>>> response.status_code
200
>>> response.request.headers["Authorization"]
'Bearer ghp_b...Tx'


Ваш пользовательский TokenAuth создал хорошо отформатированную строку для заголовка Authorization. Это дает вам более интуитивно понятный и многократно используемый способ работы со схемами аутентификации на основе токенов, подобными тем, которые требуются в некоторых частях API GitHub.

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

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

Некачественные механизмы аутентификации могут привести к уязвимостям в системе безопасности. Если по какой-либо причине службе не требуется специальный механизм аутентификации, лучше всего использовать проверенный метод, такой как встроенная базовая аутентификация или OAuth- например, через Запросы-OAuthlib.

Пока вы думаете о безопасности, рассмотрите возможность использования сертификатов TLS/SSL с запросами.

Безопасное взаимодействие с Серверами

Всякий раз, когда данные, которые вы пытаетесь отправить или получить, являются конфиденциальными, безопасность становится жизненно важной. Для взаимодействия с защищенными сайтами по протоколу HTTP необходимо установить зашифрованное соединение с использованием протокола безопасности транспортного уровня (TLS). Протокол TLS является преемником протокола Secure Sockets Layer (SSL) и обеспечивает повышенную безопасность и эффективность защищенных коммуникаций. Тем не менее, программисты по-прежнему часто используют термин SSL вместо TLS.

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

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

>>> import requests

>>> requests.get(
...     "https://internal-api.company.com",
...     verify="/path/to/company-ca.pem"
... )
<Response [200]>


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

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

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


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

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

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

Повышение производительности

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

Примечание: Requests не поддерживает асинхронные HTTP-запросы напрямую. Если вам нужна поддержка асинхронности в вашей программе, то вам следует попробовать AIOHTTP или HTTPX. Последняя библиотека в целом совместима с синтаксисом запросов.

Даже в синхронном коде есть несколько важных методов, которые вы можете использовать для оптимизации ваших HTTP-запросов и предотвращения снижения производительности.

Установить тайм-ауты запросов

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

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

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

>>> requests.get("https://api.github.com", timeout=0.01)
Traceback (most recent call last):
  ...
requests.exceptions.ConnectTimeout:
⮑ HTTPSConnectionPool(host='api.github.com', port=443):
⮑ Max retries exceeded with url: / (Caused by ConnectTimeoutError(...))


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

Вы также можете передать кортеж в timeout со следующими двумя элементами:

  1. Время ожидания подключения: время, в течение которого клиент может установить соединение с сервером
  2. Тайм-аут чтения: Время ожидания ответа после того, как клиент установит соединение

Оба этих элемента должны быть числами и могут иметь тип int или float:

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


Если запрос устанавливает соединение в течение 3.05 секунды и получает данные в течение 5 секунд после установления соединения, то ответ будет возвращен в том же виде, в каком он был получен ранее. Если время выполнения запроса истекло, функция вызовет либо ConnectTimeout, либо ReadTimeout, которые являются подклассами более общего исключения Timeout:

timeout_catcher.py
import requests
from requests.exceptions import Timeout

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

Ваша программа может перехватить исключение Timeout и отреагировать соответствующим образом.

Повторное использование Соединений с Объектами Сеанса

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

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

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

persist_info_with_session.py
 1import requests
 2from custom_token_auth import TokenAuth
 3
 4TOKEN = "<YOUR_GITHUB_PA_TOKEN>"
 5
 6with requests.Session() as session:
 7    session.auth = TokenAuth(TOKEN)
 8
 9    first_response = session.get("https://api.github.com/user")
10    second_response = session.get("https://api.github.com/user")
11
12print(first_response.headers)
13print(second_response.json())

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

В строке 7 вы прикрепляете учетные данные пользователя GitHub к объекту session, используя свой пользовательский TokenAuth. Вам нужно сделать это только один раз за сеанс, а затем вы можете выполнить несколько аутентифицированных запросов. Запросы будут сохранять учетные данные до тех пор, пока длится сеанс.

В строках 9 и 10 вы затем делаете два запроса к аутентифицированному пользовательскому API, используя session.get() вместо requests.get().

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

Повторите неудачные запросы

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

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

retry_twice.py
import requests
from requests.adapters import HTTPAdapter
from requests.exceptions import RetryError
from urllib3.util.retry import Retry

retry_strategy = Retry(
    total=2,
    status_forcelist=[429, 500, 502, 503, 504]
)
github_adapter = HTTPAdapter(max_retries=retry_strategy)

with requests.Session() as session:
    session.mount("https://api.github.com", github_adapter)
    try:
        response = session.get("https://api.github.com/")
    except RetryError as err:
        print(f"Error: {err}")

В этом примере вы настроили свой сеанс таким образом, чтобы он повторялся максимум два раза, если ваш запрос к API GitHub не сработает должным образом. Объект Retry предоставляет вам детальный контроль над тем, какие коды состояния должны инициировать повторные попытки.

Аргумент max_retries принимает либо целое число, либо объект Retry. Использование объекта Retry позволяет детально контролировать, какие ошибки повторяются. В то время как вы все еще можете передать простое целое число для базовых случаев, использование объекта Retry является современным подходом.

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

Примечание: Хотя реализация, показанная выше, работает, вы не увидите никаких последствий от повторной попытки, если только что-то не в порядке с вашим сетевым подключением или серверами GitHub.

Если вы хотите поэкспериментировать с кодом, построенным на основе этого примера, и посмотреть, когда будут повторяться попытки, то вам повезло. Вы можете скачать материалы для этого руководства и ознакомиться с retry_thrice.py:

Получите свой код: Нажмите здесь, чтобы загрузить бесплатный пример кода, который показывает, как использовать библиотеку запросов Python.

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

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

Заключение

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

В этом руководстве вы узнали, как:

  • Делайте запросы, используя различные HTTP-методы, такие как GET, POST, и PUT
  • Настраивайте свои запросы, изменяя заголовки, аутентификацию, строки запроса и тексты сообщений
  • Проверьте данные, которые вы отправляете на сервер, и данные, которые сервер отправляет вам обратно
  • .
  • Работа с Проверкой сертификатов TLS/SSL
  • Эффективно использовать запросы с помощью max_retries, timeout, сеансов и транспортных адаптеров

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

Получите свой код: Нажмите здесь, чтобы загрузить бесплатный пример кода, который показывает, как использовать библиотеку запросов Python.

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

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

Эти часто задаваемые вопросы относятся к наиболее важным понятиям, которые вы рассмотрели в этом руководстве. Нажмите на переключатель Показывать/скрывать рядом с каждым вопросом, чтобы открыть ответ.

Нет, библиотека запросов не является частью стандартной библиотеки Python. Вам необходимо установить ее отдельно с помощью pip.

Вы создаете GET запрос на Python, используя функцию requests.get(), передавая желаемый URL в качестве аргумента.

Вы отправляете POST данные с запросами, передавая данные в параметр data в функции requests.post(). Для данных в формате JSON используйте вместо этого параметр json.

Вы добавляете заголовки к запросам в Python, передавая словарь заголовков параметру headers в функциях requests.get() или requests.post().

response.text возвращает содержимое ответа в виде строки, в то время как response.content возвращает его в виде необработанных байт. Используйте response.text, если вы хотите работать с данными в виде строки.

<отметить класс="marker-highlight"> Пройдите тест: Проверьте свои знания с помощью нашего интерактивного теста ”Библиотека запросов Python". По завершении вы получите оценку, которая поможет вам отслеживать прогресс в обучении:

<время работы/> Python’s Requests Library (Guide)

Интерактивная викторина

Библиотека запросов Python

Проверьте свое понимание библиотеки запросов Python для выполнения HTTP-запросов и взаимодействия с веб-службами.

<статус завершения article-slug="python-requests" class="btn-group mb-0" data-api-article-bookmark-url="/api/v1/articles/python-requests/bookmark/" статус завершения data-api-article-url="/api/v1/articles/python-запросы/завершение_статуса/"> <кнопка поделиться bluesky-text="Интересная статья на #Python от @realpython.com :" email-body="Ознакомьтесь с этой статьей о Python: Библиотека запросов %0A%0APython (руководство)" email-subject="Статья о Python для вас" twitter-text="Интересная статья о #Python от @realpython:" url="https://realpython.com/python-requests /" url-title="Библиотека запросов Python (руководство)">

Смотрите сейчас, к этому уроку прилагается соответствующий видеокурс, созданный командой Real Python. Посмотрите его вместе с письменным руководством, чтобы углубить свое понимание: Создание HTTP-запросов с помощью Python

Back to Top