Оглавление
- Начало работы с запросами
- Запрос 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 является GET
. GET
метод указывает на то, что вы пытаетесь получить, или получить данные из указанного ресурса. Чтобы сделать 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
между 200
, 400
и 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 включают в себя POST
, PUT
, DELETE
, HEAD
, PATCH
, и OPTIONS
. requests
предоставляет метод с аналогичной сигнатурой 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
для каждого метода. Далее вы более внимательно взгляните на POST
, PUT
и PATCH
методы , и узнаете, как они отличаются от других типов запросов.
Тело сообщения
В соответствии со спецификацией HTTP, POST
, PUT
, и менее распространенные 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 через json
, requests
сериализует ваши данные и добавит правильный Content-Type
заголовок для вас.
httpbin.org большой ресурс , созданный автором requests
– Kenneth 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)
Когда вы устанавливаете HTTPAdapter
, github_adapter
к session
, session
будет придерживаться своей конфигурации для каждого запроса к https://api.github.com.
Тайм-ауты, транспортные адаптеры и сеансы предназначены для обеспечения эффективности вашего кода и устойчивости вашего приложения.
Вывод
Вы прошли долгий путь в изучении мощной requests
библиотеки Python .
Теперь вы можете:
- Сделать запросы с помощью множества различных методов , таких как HTTP
GET
,POST
, иPUT
- Настроить свои запросы, изменив заголовки, аутентификацию, строки запросов и тела сообщений.
- Проверить данные, которые вы отправляете на сервер, и данные, которые сервер отправляет вам обратно
- Работать с проверкой SSL-сертификата
- Использовать
max_retries
,timeout
, сеансы и транспортные адаптеры
Благодаря тому, что вы научились пользоваться requests
, вы готовы исследовать широкий мир веб-сервисов и создавать потрясающие приложения, используя данные, которые они предоставляют.