Пример работы с API сайта mos.ru

Выгрузим координаты избирательных участков Москвы, обратившись к API сайта mos.ru. Для отправления запроса нам понадобится модуль requests:

In [1]:
import requests

Как выглядят запросы с API, если их отправлять не автоматически, через Python, а формировать вручную? Это просто ссылки особого вида, где помимо основной ссылки добавляются параметры и их значения. Например, можно написать какой-нибудь текстовый шаблон такого вида:

"https://myapi.ru/data/id={id0}?key={key0}",

где вместо id0 будет подставляться идентификатор набора данных, который нас интересует, а вместо key0 – ключ доступа к API.

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

Если API не полностью открытый, к нему нужно получить доступ. Обычно процедура его получения описывается в документации к API. После регистрации пользователь получает ключ доступа – обычный набор символов, похожий на пароль, который нужно всегда указывать в запросе. Получим ключ доступа для API mos.ru по инструкции и сохраним его в Python:

In [2]:
key = "9b36f3ab185cbac617668968752505d9"

Если посмотрим на документацию, заметим, что все запросы к API начинаются со слова GET. В Python это будет реализовываться с помощью функции get() из модуля requests. Для примера запросим текущую версию API:

In [3]:
resp = requests.get("https://apidata.mos.ru/version")
resp
Out[3]:
<Response [200]>

Сам объект resp от нас скрыт, код [200] означает, что ответ получен. Вызовем результат в формате json():

In [4]:
d = resp.json()
d['Version']   # версия
Out[4]:
1

Если снова обратимся к документации, заметим, что в ней описаны все параметры, которые мы можем задать в запросе. Сформируем строку запроса к набору данных с id = 961 (нам нужен этот набор с данными по УИКам Москвы:

In [5]:
# rows – выдает все строки
# доклеиваем ключ к API – без него не даст доступ

resp = requests.get("https://apidata.mos.ru/v1/datasets/961/rows?api_key="
                    +key)
resp # все ок, есть ответ на запрос
Out[5]:
<Response [200]>

Снова вызовем результат в формате json, в данном случае это список словарей:

In [6]:
# один словарь – один УИК

results = resp.json()

Посмотрим на первый элемент – первый УИК в таблице на сайте:

In [45]:
results[0]
Out[45]:
{'global_id': 1006662927,
 'Number': 1,
 'Cells': {'global_id': 1006662927,
  'District_RF': 'район Орехово-Борисово Южное',
  'PollStationNumber': 1981,
  'PollStationName': 'Избирательный участок № 1981',
  'PollStationAddress': 'Воронежская улица, дом 46, корпус 3',
  'PollStationAddressExtraInfo': 'ГБОУ СОШ № 949',
  'PollStationContactPhone': '(495) 398-89-12',
  'PollPlaceAddress': 'Воронежская улица, дом 46, корпус 3',
  'PollPlaceAddressExtraInfo': 'ГБОУ СОШ № 949',
  'PollPlaceContactPhone': '(495) 398-89-12',
  'PolIAddressesList': [{'PolIAddressesList': 'Гурьевский проезд, дом 29, корпус 1'},
   {'PolIAddressesList': 'Гурьевский проезд, дом 31, корпус 1'},
   {'PolIAddressesList': 'Гурьевский проезд, дом 31, корпус 2'},
   {'PolIAddressesList': 'Гурьевский проезд, дом 35/58'}],
  'AdmArea_RF': 'Южный административный округ',
  'geoData': {'type': 'Point',
   'coordinates': [37.753847, 55.608810999999996]}}}

Теперь можем вызывать любые поля – любые записи по ключам в словаре. Например, вытащим отсюда адреса, относящиеся к УИКу:

In [7]:
# ключ Cells и внутри ключ PolIAddressesList
results[0]['Cells']['PolIAddressesList']
Out[7]:
[{'PolIAddressesList': 'Гурьевский проезд, дом 29, корпус 1'},
 {'PolIAddressesList': 'Гурьевский проезд, дом 31, корпус 1'},
 {'PolIAddressesList': 'Гурьевский проезд, дом 31, корпус 2'},
 {'PolIAddressesList': 'Гурьевский проезд, дом 35/58'}]

Теперь вытащим координаты:

In [8]:
# ключ Cells, внутри ключ geoData и внутри ключ coordinates

results[0]['Cells']['geoData']['coordinates']
Out[8]:
[37.753847, 55.608810999999996]

Теперь осталось запустить цикл по всем элементам списка и сохранить номер участка и его кооржинаты в список:

In [9]:
dat = []
for i in results:
    uik = i['Cells']['PollStationNumber']
    lat, lon = i['Cells']['geoData']['coordinates']
    dat.append([uik, lat, lon])

Превратим список списков в датафрейм:

In [11]:
import pandas as pd
df = pd.DataFrame(dat)
In [12]:
df.head()
Out[12]:
0 1 2
0 1981 37.753847 55.608811
1 932 37.822819 55.795013
2 1014 37.827419 55.754405
3 1982 37.753847 55.608811
4 1310 37.823242 55.694921

Переименуем столбцы:

In [14]:
df.columns = ['uik', 'lat', 'lon']
df.head()
Out[14]:
uik lat lon
0 1981 37.753847 55.608811
1 932 37.822819 55.795013
2 1014 37.827419 55.754405
3 1982 37.753847 55.608811
4 1310 37.823242 55.694921

Готово!