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

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

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

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

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

  • Make requests с использованием наиболее распространенных методов HTTP

  • Customize заголовки и данные ваших запросов, используя строку запроса и тело сообщения

  • Inspect данные из ваших запросов и ответов

  • Сделатьauthenticated запросов

  • Configure ваши запросы, чтобы предотвратить резервное копирование или замедление вашего приложения

Хотя я попытался включить столько информации, сколько вам нужно для понимания функций и примеров, включенных в эту статью, я предполагаю, чтоverybasic general knowledge of HTTP. Тем не менее, вы все равно можете быть в состоянии следовать в любом случае хорошо.

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

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

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

$ pip install requests

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

$ pipenv install requests

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

import requests

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

Запрос GET

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

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

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

>>>

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

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

Ответ

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

>>>

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

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

Коды состояния

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

Например, статус200 OK означает, что ваш запрос был успешным, тогда как статус404 NOT FOUND означает, что ресурс, который вы искали, не был найден. Также естьmany other possible status codes, чтобы дать вам конкретное представление о том, что произошло с вашим запросом.

Получив доступ к.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.')

Technical Detail: ЭтотTruth Value Test стал возможным, потому что__bool__() is an overloaded method наResponse.

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

Имейте в виду, что этот методnot проверяет, что код состояния равен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. Если код состояния указывает на успешный запрос, программа продолжит работу без возникновения этого исключения.

Further Reading: Если вы не знакомы сf-strings Python 3.6, я рекомендую вам воспользоваться ими, поскольку они являются отличным способом упростить ваши форматированные строки.

Теперь вы много знаете о том, как обращаться с кодом состояния ответа, полученного вами с сервера. Однако когда вы делаете запрос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 дает вам доступ к необработанным байтам полезной нагрузки ответа, вы часто можете захотеть преобразовать их вstring, используя кодировку символов, такую ​​как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 на основеheaders ответа, если вы не укажете один. Вы можете предоставить явное кодирование, установив.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 - передача значений через параметрыquery string в URL-адресе. Чтобы сделать это с помощьюget(), вы передаете данные вparams. Например, вы можете использовать API GitHubSearch для поиска библиотеки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')],
... )

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

>>>

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

Строки запроса полезны для параметризации запросов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, который является проприетарным заголовком GitHubAccept, содержание которого является особым форматом 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'})

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

>>>

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

Однако, если вам нужно отправить данные 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, требующего аутентификации, является APIAuthenticated User GitHub. Эта конечная точка предоставляет информацию о профиле аутентифицированного пользователя. Чтобы сделать запрос к API аутентифицированного пользователя, вы можете передать свое имя пользователя и пароль GitHub в виде кортежа вget():

>>>

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

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

>>>

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

Когда вы передаете свое имя пользователя и пароль в кортеже параметруauth,requests применяет учетные данные, используя HTTP-кодBasic access authentication scheme под капотом.

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

>>>

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

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

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

Note:requests uses a package called certifi для предоставления центров сертификации. Это позволяетrequests узнать, каким органам власти он может доверять. Поэтому вам следует часто обновлятьcertifi, чтобы ваши соединения оставались максимально безопасными.

Спектакль

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

Таймауты

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

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

>>>

>>> requests.get('https://api.github.com', timeout=1)

>>> requests.get('https://api.github.com', timeout=3.05)

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

отYou can also pass a tuple доtimeout, причем первый элемент представляет собой тайм-аут соединения (время, которое позволяет клиенту установить соединение с сервером), а второй - тайм-аут чтения (время ожидания ответ после того, как ваш клиент установил соединение):

>>>

>>> requests.get('https://api.github.com', timeout=(2, 5))

Если запрос устанавливает соединение в течение 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 и отреагировать соответствующим образом.

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

До сих пор вы имели дело с API высокого уровняrequests, такими как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, оно сохраняет это соединение в пуле соединений. Когда ваше приложение снова хочет подключиться к тому же серверу, оно будет повторно использовать соединение из пула, а не устанавливать новое.

Макс повторов

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

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

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

Заключение

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

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

  • Выполняйте запросы с использованием различных HTTP-методов, таких какGET,POST иPUT.

  • Настройте свои запросы, изменив заголовки, аутентификацию, строки запросов и тела сообщений.

  • Проверьте данные, которые вы отправляете на сервер, и данные, которые сервер отправляет вам обратно

  • Работа с проверкой SSL-сертификата

  • Эффективно используйтеrequests, используяmax_retries,timeout, сеансы и транспортные адаптеры

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

Related