Requests в Python — Примеры выполнения HTTP запросов (Часть 2)

Продолжаем рассматривать HTTP-запросы в Python и то, как с ними работать. В предыдущей части этого материала мы раскрыли много тем – использование метода GET, работу с объектом Response, как работать с параметрами запроса, HTTP-заголовками.

Теперь мы рассмотрим различные аспекты работы с Requests. Чтобы лучше понимать то, что будет раскрыто далее, настоятельно рекомендуется прочитать предыдущую часть этого материала. 

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

Чтобы изменить 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'},

)

 

# просмотр нового массива `text-matches` с предоставленными данными

# о поиске в пределах результатов

json_response = response.json()

repository = json_response['items'][0]

print(f'Text matches: {repository["text_matches"]}')

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

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

HTTP-методы в Requests – примеры

Кроме GET, большой популярностью пользуются такие методы, как POST, PUT, DELETE, HEAD, PATCH, OPTIONS. Для каждого из них существует собственная сигнатура, которая во многом напоминает метод get()

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

Настоятельно рекомендуется воспользоваться сайтом httpbin.org. Это очень полезный веб-ресурс, который был создан тем человеком, который и внедрил библиотеку, которую мы сегодня рассматриваем – Кеннетом Рейтцом. С помощью этого сервиса можно выполнять тестовые запросы. Здесь можно составить пробный запрос и получить ответ с требуемой информацией. 

Давайте в качестве примера рассмотрим стандартный запрос с применением 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'

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

Выполнение анализа запроса

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

Если открыть .request, то можно посмотреть на PreparedRequest

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

Аутентификация с помощью Python Requests

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

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

Одним из вариантов API, требующего аутентификацию, является этот (ссылка на GitHub). Это итоговая точка веб-сервиса, поставляющая данные о профиле пользователя, который прошел идентификацию. Для отправки запроса API-интерфейсу пользователя, который прошел аутентификацию, используя кортеж в 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, то используется базовая схема аутентификации. Следовательно, вы можете создать тот же самый запрос, передав детальные учетные данные базовой аутентификации, воспользуясь 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.

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

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'))

Как видим, это делалось с помощью подкласса AuthBase и дальнейшей имплементации __call__().

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

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

Теперь давайте рассмотрим использование requests в SSL-сертификатах.

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

Таймауты

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

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

Также возможна непосредственная передача кортежа. Это – таймаут соединения (время, в течение которого клиент может установить соединение с сервером), а второй – таймаут чтения (время ожидания ответа, как только клиент установил соединение). 

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

<Response [200]>

Если соединение устанавливается на протяжении двух секунд и получает информацию в течение 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')

Объект Session

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

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

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

Python

import requests

from getpass import getpass

 

# используя менеджер контента, можно убедиться, что ресурсы, применимые

# во время сессии будут свободны после использования

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')

 

# здесь можно изучить ответ 

print(response.headers)

print(response.json())

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

Максимальное количество повторов запроса

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

Допустим, вам нужно, чтобы все запросы к https://api.github.com повторялись трижды перед тем, как появится ошибка соединения. Для этого необходимо написать следующий код:

import requests

from requests.adapters import HTTPAdapter

from requests.exceptions import ConnectionError

 

github_adapter = HTTPAdapter(max_retries=3)

 

session = requests.Session()

 

# использование `github_adapter` для всех запросов, которые начинаются с указанным URL

session.mount('https://api.github.com', github_adapter)

 

try:

    session.get('https://api.github.com')

except ConnectionError as ce:

    print(ce)

ОфисГуру
Adblock
detector