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

1 июня, 2020

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

Оглавление

  • Начало работы с запросами
  • Запрос GET
  • Ответ
    • Коды состояния
    • Содержание
    • Заголовки
  • Параметры строки запроса
  • Заголовки запроса
  • Другие методы HTTP
  • Тело сообщения
  • Проверка вашего запроса
  • Аутентификация
  • Проверка SSL сертификата
  • Представление
    • Таймауты
    • Объект сеанса
    • Макс повторов
  • Вывод

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

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

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

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

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

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

Начало работы с requests

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

$ pip install requests

Если вы предпочитаете использовать Pipenv для управления пакетами Python, вы можете запустить следующее:

$ pipenv install requests

После установки requests вы можете использовать его в своем приложении. Импорт requests выглядит так:

import requests

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

Запрос GET

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

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

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

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

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

Ответ

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

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

В этом примере вы захватили возвращаемое значение 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.

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

Поэтому вы можете упростить последний пример, переписав if оператор:

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

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

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

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

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

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

import requests
from requests.exceptions import HTTPError

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

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

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

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

Содержание

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

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

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

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

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

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

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

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

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

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

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

Заголовки

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

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

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

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

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

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

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

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

Параметры строки запроса

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

import requests

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

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

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

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

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

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

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

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

Заголовки запроса

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

import requests

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

# View the new `text-matches` array which provides information
# about your search term within the results
json_response = response.json()
repository = json_response['items'][0]
print(f'Text matches: {repository["text_matches"]}')

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

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

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

Помимо GET другие популярные методы HTTP включают в себя POSTPUTDELETEHEADPATCH, и OPTIONSrequests предоставляет метод с аналогичной сигнатурой get() для каждого из этих методов HTTP:

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

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

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

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

Заголовки, тела ответов, коды состояния и многое другое возвращаются в Response для каждого метода. Далее вы более внимательно взгляните на POSTPUT и PATCH методы , и узнаете, как они отличаются от других типов запросов.

Тело сообщения

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

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

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

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

Вы также можете отправить те же данные в виде списка кортежей:

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

Однако если вам необходимо отправить данные JSON, вы можете использовать этот json параметр. Когда вы передадите данные JSON через jsonrequests сериализует ваши данные и добавит правильный Content-Type заголовок для вас.

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

Проверка вашего запроса

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

Вы можете просмотреть PreparedRequest, зайдя в .request:

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

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

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

Аутентификация

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

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

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

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

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

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

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

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

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

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

import requests
from requests.auth import AuthBase

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

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

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


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

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

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

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

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

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

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

Если вы хотите отключить проверку SSL-сертификата, вы переходите False к параметру функции запроса verify:

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

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

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

Представление

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

Таймауты

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

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

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

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

Вы также можете передать кортеж , чтобы timeout с первым элементом ЯВЛЯЮЩЕЙСЯ таймаут соединения (время позволяет клиенту установить соединение с сервером), а второй для чтения тайм – аут (время будет ждать ответа , как только ваш клиент установил соединение):

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

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

import requests
from requests.exceptions import Timeout

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

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

Объект сеанса

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

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

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

import requests
from getpass import getpass

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

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

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

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

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

Max Retries

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

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

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

github_adapter = HTTPAdapter(max_retries=3)

session = requests.Session()

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

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

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

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

Вывод

Вы прошли долгий путь в изучении мощной requests библиотеки Python .

Теперь вы можете:

  • Сделать запросы с помощью множества различных методов , таких как HTTP GETPOST, и PUT
  • Настроить свои запросы, изменив заголовки, аутентификацию, строки запросов и тела сообщений.
  • Проверить данные, которые вы отправляете на сервер, и данные, которые сервер отправляет вам обратно
  • Работать с проверкой SSL-сертификата
  • Использовать  max_retriestimeout, сеансы и транспортные адаптеры

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


Совершенствуй знания каждый день у нас в Телеграм-каналах

Вопросы, реклама — VK | Telegram