И наконец рассмотрим применение модуля requests для создания и отправки запросов по протоколу HTTP — и научимся взаимодействовать с API-сервисами.

HTTP

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

Эти уровни передачи определены в стандарте OSI (The Open Systems Interconnection model, модель взаимодействия открытых систем). На каждом уровне описаны протоколы, по которым происходит обмен данными. Протокол — это набор правил, который определяет процесс обмена данными между различными устройствами или программами.

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

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

Для обмена данными между программами в компьютерных сетях используются различные протоколы прикладного уровня. Один из самых популярных протоколов — HTTP (HyperText Transfer Protocol, протокол передачи гипертекста). Он создавался для передачи гипертекстовых документов формата HTML (веб-страницы), однако в настоящее время используется для обмена произвольными данными: графическими и видеофайлами, документами и т. д.

Протокол HTTP работает по принципу «запрос — ответ». В протоколе описаны виды запросов, правила формирования запросов и возможные варианты ответов на запросы. Ответы в протоколе HTTP имеют коды состояния, которые представляют собой числовые значения. По коду состояния всегда можно определить, верно ли был обработан запрос или произошла ошибка. Например, вам, скорее всего, знаком код состояния 404, который означает, что запрошенный объект (чаще всего веб-страница) не был найден.

В протоколе HTTP описаны различные виды запросов: на получение данных (GET), на передачу данных (POST), на добавление и изменение данных (PUT), на удаление данных (DELETE) и др.

Итак, многие сетевые программы взаимодействуют по протоколу HTTP. Часто разработчикам веб-сервисов нужно отправлять в качестве ответа на запросы не веб-страницы, а данные, например информацию о географических объектах в формате JSON или графический файл с определённой областью географической карты. Порой это помогает расширить функционал сервиса. К примеру, добавить авторизацию через соцсети.

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

Реализация взаимодействия с сервисом через такой набор правил происходит посредством API (Application Programming Interface). Правила API описывают возможные запросы к сервису и ответы сервиса на эти запросы. Так, API отдельного веб-сервиса можно назвать нестандартным протоколом этого сервиса, действующим над протоколом HTTP.

Для работы с API можно не писать программу, а просто выполнить запрос в браузере, так как он также работает по протоколу HTTP.

Static API

Воспользуемся в качестве примера одним из API сервиса Яндекс Карт — Static API. Static API возвращает изображение карты в ответ на HTTPS-запрос. Добавляя в URL разные параметры и задавая их значения, вы можете определить центр карты, её размер и область показа, отметить нужные объекты и отобразить пробки. Данные будут обновляться при каждом новом обращении, поэтому карта всегда будет актуальной.

Обратите внимание: у каждого API есть условия использования, которые нужно обязательно изучить перед началом работы и которым нужно следовать при разработке программ на основе API. Например, для Static API в бесплатной версии API Яндекс Карт изображение карты обязательно должно быть размещено на общедоступном сайте или в приложении. Есть и другие условия бесплатного использования.

Давайте сделаем первый запрос к Static API. Для этого надо открыть документацию и понять, каким должен быть запрос. Запрос к Static API имеет следующий формат: https://static-maps.yandex.ru/1.x/?. Воспользуемся примерами использования и выполним в браузере следующий запрос:
https://static-maps.yandex.ru/1.x/?ll=37.677751,55.757718&spn=0.016457,0.00619&l=map

Параметр ll отвечает за координаты центра карты (через запятую указываются долгота и широта в градусах). Параметр spn определяет область показа (протяжённость карты в градусах по долготе и широте). Параметр l определяет тип карты (в запросе используется тип map — схема). Все возможные параметры запроса можно посмотреть в документации.

В ответе на запрос сервер пришлёт часть карты по запрошенным координатам.

Чтобы воспользоваться API в программе, нужно из неё отправить такой же запрос, а затем получить ответ сервера. Для удобного формирования HTTP-запросов и получения ответов можно использовать библиотеку requests.

Библиотека requests является нестандартной и устанавливается следующей командой:

pip install requests

В библиотеке requests функции для формирования HTTP-запросов называются так же, как и сами запросы. Например, для выполнения GET-запроса используем функцию get():

from requests import get

response = get("https://static-maps.yandex.ru/1.x/?"
             "ll=37.677751,55.757718&"
             "spn=0.016457,0.00619&"
             "l=map")
print(response)

Вывод программы:

<Response [200]>

Функция get() вернула ответ HTTP-сервера с кодом 200. Значит, запрос был обработан успешно. Для получения данных из ответа сервера воспользуемся атрибутом content. В этом атрибуте находятся данные в виде последовательности байтов. Из документации Static API известно, что ответом сервера на успешный запрос должен быть графический файл формата PNG. Запишем данные из ответа сервера в новый файл с расширением .png. Для этого откроем файл функцией open() на запись в бинарном режиме (wb), так как будем сохранять байты, а не текст. А затем воспользуемся методом write() созданного файлового объекта:

with open("map.png", "wb") as file:
    file.write(response.content)

В папке с программой будет создан файл map.png с запрошенной областью карты.

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

params = {"ll": "37.677751,55.757718",
          "spn": "0.016457,0.00619",
          "l": "map"}
response = get("https://static-maps.yandex.ru/1.x/", params=params)

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

from requests import get, ConnectionError

params = {"ll": "37.677751,55.757718",
          "spn": "0.016457,0.00619",
          "l": "map"}
try:
    response = get("https://static-maps.yandex.ru/1.x/", params=params)
except ConnectionError:
    print("Проверьте подключение к сети.")
else:
    with open("map.png", "wb") as file:
        file.write(response.content)

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

API Яндекс Диск

Рассмотрим ещё один пример взаимодействия с API. Яндекс Диск — это облачный сервис для хранения файлов и обмена ими. Он предоставляет API для сохранения файлов и организации доступа к ним. Полный список запросов к API и формат ответов сервера находится в документации.

Для работы с API Яндекс Диска требуется авторизация пользователя по протоколу OAuth 2.0. Открытый протокол авторизации OAuth 2.0 обеспечивает предоставление третьей стороне ограниченного доступа к защищённым ресурсам пользователя без передачи ей логина и пароля. Вместо логина и пароля авторизация производится по OAuth-токену. Токен — это уникальная для каждого пользователя строка-ключ для доступа с помощью API к файлам в облаке.

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

  1. Заполнить поле «Название сервиса».
  2. Выбрать вариант платформы «Веб-сервисы».
  3. Выбрать значение «Подставить URL для разработки» в поле Callback URL.
  4. В качестве доступных сервису данных указать «Яндекс Диск REST API» и выдать все четыре возможных права доступа.
  5. Нажать кнопку «Создать приложение».

После выполнения указанных действий появится окно, в котором будут указаны значения для полей ClientID, Client secret и Redirect URL. Эти значения мы будем использовать для получения токена по протоколу авторизации OAuth 2.0. Данный протокол реализован в библиотеке requests-oauthlib.

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

Напишем программу с авторизацией сервиса и получением токена. Значения переменных client_id и client_secret нужно скопировать из полей ClientID, Client secret со страницы информации о зарегистрированном сервисе.

from requests_oauthlib import OAuth2Session
from requests import get, post, put, delete


client_id = ""
client_secret = ""
auth_url = "https://oauth.yandex.ru/authorize"
token_url = "https://oauth.yandex.ru/token"
oauth = OAuth2Session(client_id=client_id)
authorization_url, state = oauth.authorization_url(auth_url, force_confirm="true")
print("Перейдите по ссылке, авторизуйтесь и скопируйте код:", authorization_url)
code = input("Вставьте одноразовый код: ")
token = oauth.fetch_token(token_url=token_url,
                          code=code,
                          client_secret=client_secret)
access_token = token["access_token"]
print(access_token)

Переменная token является словарём, в котором необходимый для выполнения запросов токен находится по ключу access_token.

Полученный на этапе авторизации токен необходимо передавать во всех запросах к API. Для этого нужно заполнять в заголовке запроса поле Authorization значением OAuth <ваш токен>.

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

Все возможные запросы к сервису, их формат и ответы сервера можно посмотреть в документации.

Выполним GET-запрос по адресу https://cloud-api.yandex.net/v1/disk для получения информации о состоянии облачного хранилища:

headers = {"Authorization": f"OAuth {access_token}"}
r = get("https://cloud-api.yandex.net/v1/disk", headers=headers)
print(r.json())

Данные в ответе на запрос имеют формат JSON. Они преобразуются в словарь методом json(). В ответе содержится информация о максимальном размере файла на диске (поле max_file_size), о размере диска (поле total_space), об использованном объёме (used_space) и др. Полное описание полей ответа можно посмотреть в документации.

Создадим в корневой папке диска новую папку Тест API. Скопируем файл map.png, полученный в примерах для Static API, в эту папку. Для создания папки потребуется выполнить PUT-запрос по адресу https://cloud-api.yandex.net/v1/disk/resources с обязательным параметром path, в котором должен быть записан путь к создаваемой папке.

params = {"path": "Тест API"}
r = put("https://cloud-api.yandex.net/v1/disk/resources", headers=headers, params=params)
print(r)

В случае успешного запроса программа выведет код ответа <Response [201]>, а в корневой папке облачного диска будет создана папка Тест API:

dir

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

  • GET-запрос по адресу https://cloud-api.yandex.net/v1/disk/resources/upload для получения ссылки на загрузку файла в облако. Если запрос будет успешен, то URL для загрузки файла будет в поле href JSON-ответа сервера.
  • PUT-запрос по URL из предыдущего пункта. В аргумент files функции put передаётся словарь с ключом file и значением — файловым объектом, открытым в режиме бинарного чтения rb. Передавать токен в данном запросе не нужно.

Выполним указанные запросы в программе:

params = {"path": "Тест API/map.png"}
r = get("https://cloud-api.yandex.net/v1/disk/resources/upload",
        headers=headers, params=params)
href = r.json()["href"]
files = {"file": open("map.png", "rb")}
r = put(href, files=files)
print(r)

В результате успешного запроса программа выведет <Response [201]>, а в папке Тест API в облаке появится файл map.png:

file

Попробуйте реализовать другие операции с хранилищем через запросы к API в соответствии с документацией.

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

Отмечайте параграфы как прочитанные чтобы видеть свой прогресс обучения

Вступайте в сообщество хендбука

Здесь можно найти единомышленников, экспертов и просто интересных собеседников. А ещё — получить помощь или поделиться знаниями.
Вступить
Сообщить об ошибке
Предыдущий параграф6.2. Модуль pandas

Тут мы изучим назначение и базовые возможности модуля pandas для обработки и анализа табличных структур данных.

Следующий параграф7.1. Как работать с системой проверки заданий