{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "### Пример работы с API сайта mos.ru\n", "\n", "Выгрузим координаты избирательных участков Москвы, обратившись к API сайта mos.ru. \n", "Для отправления запроса нам понадобится модуль `requests`:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import requests" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Как выглядят запросы с API, если их отправлять не автоматически, через Python, а формировать вручную? Это просто ссылки особого вида, где помимо основной ссылки добавляются параметры и их значения. Например, можно написать какой-нибудь текстовый шаблон такого вида:\n", "\n", " \"https://myapi.ru/data/id={id0}?key={key0}\",\n", " \n", "где вместо `id0` будет подставляться идентификатор набора данных, который нас интересует, а вместо `key0` – ключ доступа к API. \n", "\n", "Какие параметры могут присутствовать в запросе, зависит от устройства конкректного API. API можно рассматривать как базу данных с разработанным интерфейсом. Пользователь должен четко понимать, какие данные его интересуют, но при этом он не обязан знать SQL или другие языки для обращения к базам данных, достаточно посмотреть документацию к API и понять, какие параметры подставить в текстовую строку с запросом." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если API не полностью открытый, к нему нужно получить доступ. Обычно процедура его получения описывается в документации к API. После регистрации пользователь получает ключ доступа – обычный набор символов, похожий на пароль, который нужно всегда указывать в запросе. Получим ключ доступа для API mos.ru по [инструкции](https://apidata.mos.ru/) и сохраним его в Python:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "key = \"9b36f3ab185cbac617668968752505d9\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если посмотрим на [документацию](https://apidata.mos.ru/Docs), заметим, что все запросы к API начинаются со слова `GET`. В Python это будет реализовываться с помощью функции `get()` из модуля `requests`. Для примера запросим текущую версию API:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "resp = requests.get(\"https://apidata.mos.ru/version\")\n", "resp" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Сам объект `resp` от нас скрыт, код `[200]` означает, что ответ получен. Вызовем результат в формате `json()`:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d = resp.json()\n", "d['Version'] # версия" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если снова обратимся к документации, заметим, что в ней описаны все параметры, которые мы можем задать в запросе. Сформируем строку запроса к набору данных с id = 961 (нам нужен [этот набор](https://data.mos.ru/datasets/961?pageNumber=97&versionNumber=3&releaseNumber=2) с данными по УИКам Москвы:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# rows – выдает все строки\n", "# доклеиваем ключ к API – без него не даст доступ\n", "\n", "resp = requests.get(\"https://apidata.mos.ru/v1/datasets/961/rows?api_key=\"\n", " +key)\n", "resp # все ок, есть ответ на запрос" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Снова вызовем результат в формате `json`, в данном случае это список словарей:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "# один словарь – один УИК\n", "\n", "results = resp.json()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Посмотрим на первый элемент – первый УИК в таблице на сайте:" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'global_id': 1006662927,\n", " 'Number': 1,\n", " 'Cells': {'global_id': 1006662927,\n", " 'District_RF': 'район Орехово-Борисово Южное',\n", " 'PollStationNumber': 1981,\n", " 'PollStationName': 'Избирательный участок № 1981',\n", " 'PollStationAddress': 'Воронежская улица, дом 46, корпус 3',\n", " 'PollStationAddressExtraInfo': 'ГБОУ СОШ № 949',\n", " 'PollStationContactPhone': '(495) 398-89-12',\n", " 'PollPlaceAddress': 'Воронежская улица, дом 46, корпус 3',\n", " 'PollPlaceAddressExtraInfo': 'ГБОУ СОШ № 949',\n", " 'PollPlaceContactPhone': '(495) 398-89-12',\n", " 'PolIAddressesList': [{'PolIAddressesList': 'Гурьевский проезд, дом 29, корпус 1'},\n", " {'PolIAddressesList': 'Гурьевский проезд, дом 31, корпус 1'},\n", " {'PolIAddressesList': 'Гурьевский проезд, дом 31, корпус 2'},\n", " {'PolIAddressesList': 'Гурьевский проезд, дом 35/58'}],\n", " 'AdmArea_RF': 'Южный административный округ',\n", " 'geoData': {'type': 'Point',\n", " 'coordinates': [37.753847, 55.608810999999996]}}}" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "results[0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Теперь можем вызывать любые поля – любые записи по ключам в словаре. Например, вытащим отсюда адреса, относящиеся к УИКу:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[{'PolIAddressesList': 'Гурьевский проезд, дом 29, корпус 1'},\n", " {'PolIAddressesList': 'Гурьевский проезд, дом 31, корпус 1'},\n", " {'PolIAddressesList': 'Гурьевский проезд, дом 31, корпус 2'},\n", " {'PolIAddressesList': 'Гурьевский проезд, дом 35/58'}]" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# ключ Cells и внутри ключ PolIAddressesList\n", "results[0]['Cells']['PolIAddressesList']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Теперь вытащим координаты:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[37.753847, 55.608810999999996]" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# ключ Cells, внутри ключ geoData и внутри ключ coordinates\n", "\n", "results[0]['Cells']['geoData']['coordinates']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Теперь осталось запустить цикл по всем элементам списка и сохранить номер участка и его кооржинаты в список:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "dat = []\n", "for i in results:\n", " uik = i['Cells']['PollStationNumber']\n", " lat, lon = i['Cells']['geoData']['coordinates']\n", " dat.append([uik, lat, lon])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Превратим список списков в датафрейм:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "df = pd.DataFrame(dat)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
012
0198137.75384755.608811
193237.82281955.795013
2101437.82741955.754405
3198237.75384755.608811
4131037.82324255.694921
\n", "
" ], "text/plain": [ " 0 1 2\n", "0 1981 37.753847 55.608811\n", "1 932 37.822819 55.795013\n", "2 1014 37.827419 55.754405\n", "3 1982 37.753847 55.608811\n", "4 1310 37.823242 55.694921" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Переименуем столбцы:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
uiklatlon
0198137.75384755.608811
193237.82281955.795013
2101437.82741955.754405
3198237.75384755.608811
4131037.82324255.694921
\n", "
" ], "text/plain": [ " uik lat lon\n", "0 1981 37.753847 55.608811\n", "1 932 37.822819 55.795013\n", "2 1014 37.827419 55.754405\n", "3 1982 37.753847 55.608811\n", "4 1310 37.823242 55.694921" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.columns = ['uik', 'lat', 'lon']\n", "df.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Готово!" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.4" } }, "nbformat": 4, "nbformat_minor": 2 }