Начало работы с API в Python для сбора данных.

Опубликовано 22 March 2020

Дружественное (и вовсе не страшное) введение в API в Python.


API или интерфейсы прикладного программирования предоставляют простые способы извлечения (и публикации) данных. Это интерфейсы, предоставляемые серверами, которые вы можете использовать, среди прочего, для извлечения и отправки данных с использованием кода. По сути, они упрощают сложные инструкции для предоставления запроса от сервера. Их можно сравнить с официантом в ресторане. Как покровитель, вы даете инструкции официанту для еды, который затем передает запрос обратно на кухню, где повара предпринимают сложные шаги, чтобы приготовить блюдо, даже не зная всю тяжелую работу, которую он или она вкладывает в него! Затем вы получаете обратно заказанное блюдо, не разбираясь в шагах, которые понадобились, чтобы добраться туда!

API-интерфейсы обеспечивают большую эффективность при использовании статических загрузок данных (таких как файлы CSV). Они включают в себя возможность работать с быстро меняющимися данными или работать с данными, от которых вам нужен только небольшой фрагмент (скажем, сегодняшняя температура, по сравнению с загрузкой целого ряда погодных данных).

В реальном, абстрактном мире вы, вероятно, используете API каждый день, даже не подозревая об этом. Именно эта абстракция делает API настолько полезными - веб-сайты могут полагаться на API Карт Google, чтобы связать вас с указаниями, или ваш клиент Twitter позволяет публиковать данные непосредственно в вашей учетной записи.


Но как мы используем API для сбора данных?


В этом руководстве мы сначала изучим сбор данных без аутентификации, а затем еще один API, который требует от нас аутентификации. Мы начнем с выяснения, где Международная космическая станция (МКС) в настоящее время использует API Open Notify, а затем используем аутентификацию для API погоды Dark Sky для сбора интересных погодных данных. Мы закончим этот пост, исследуя, как добавить данные о Франкфуртской фондовой бирже в DataFrame Pandas!


Хорошо ... но как работает сбор данных по API в Python ?


Подобно взаимодействию с обычными веб-сайтами, когда вы хотите получить данные из API, вам нужно сделать запрос с сервера. Чтобы получить данные из API с помощью Python, нам нужно использовать библиотеку запросов (см. Рисунок!). Requests - более или менее стандартный пакет для выполнения HTTP-запросов в Python. Он очень прост в использовании благодаря своим абстракциям, особенно при работе с API.


Для начала вам может потребоваться установить библиотеку Requests, поскольку она не входит в стандартный пакет Python. Это может быть достигнуто либо через pip, либо через conda.

pip install requestsconda install requests


Запрос состоит из четырех разных частей:

1. Конечная точка (endpoint) - которая выглядит как URL к данным.

2. Метод (method) -  GET, PUT, POST или DELETE. В этом посте мы будем изучать только запросы GET.

3. Заголовки (headers) - которые предоставляют информацию, такую ​​как ключи аутентификации.

4. Данные / тело (data/body) - которые не являются частью запроса GET (так что представьте, что я их сейчас не упомянул).


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

Коды разделены на разные значения в сотнях, в зависимости от информации, которую они возвращают:

  • 1xx: предоставить информацию
  • 2xx: как правило, успешны
  • 3xx: предоставить информацию о перенаправлениях
  • 4xx: обратитесь к клиентской ошибке (наша ошибка)
  • 5xx: обратитесь к ошибке сервера (у них плохо)

Возможно, вам знакомо видеть (иногда смешную) страницу 404, когда страница не может быть найдена. Это значит то, что это код состояния.

Точно так же код состояния 200 позволяет нам знать, что все в порядке! Это то, к чему мы стремимся и надеемся получить!


API 101 - текущее местоположение МКС.


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

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

Начнем с создания запроса URL-адреса с помощью библиотеки запросов и доступа к ее атрибуту кода состояния.

Мы можем сделать это с помощью кода, описанного ниже. Выходные данные напечатаны под пунктирной линией для простоты.


import requests
response = requests.get("http://api.open-notify.org/iss-now.json")
print(response.status_code)
------------------------------------------------------------------
200


Функция .get () запрашивает объект запроса. Здесь мы можем использовать атрибут .status_code, чтобы узнать, что возвращает код состояния. В этом примере возвращенный код status_code был равен 200, что означает, что мы можем двигаться дальше!

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

Чтобы начать работать с файлами JSON, давайте импортируем библиотеку JSON, которая является частью стандартного пакета (поэтому нам не нужно ничего устанавливать). Я включил вывод кода под пунктирной линией для удобства чтения.


import requests
import json
response = requests.get("http://api.open-notify.org/iss-now.json")
print(response.json())
---------------------------------------------------------------------
{'message': 'success', 'timestamp': 1583154620,
'iss_position': {'longitude': '-28.1832', 'latitude': '7.4263'}}


Строка, возвращаемая этим ответом, довольно короткая и легко читаемая. Однако многие ответы API будут длинными и могут потребовать небольшого разбора, чтобы определить, где вы хотите искать свои данные (если вас интересует конкретная часть). Давайте используем функцию .dumps () для преобразования строки JSON в объект Python. Мы повторим часть кода для преемственности.


response = requests.get("http://api.open-notify.org/iss-now.json")
json_response = response.json()
dictionary = json.dumps(response.json(), sort_keys = True, indent = 4)
print(dictionary)
------------------------------------------------------------------------
{
"iss_position": {
"latitude": "29.2380",
"longitude": "-117.4817"
},
"message": "success",
"timestamp": 1583170890
}


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


response = requests.get("http://api.open-notify.org/iss-now.json")
json_response = response.json()
longitude = json_response['iss_position']['longitude']
latitude = json_response['iss_position']['latitude']
print('Longitude: ', longitude)
print('Latitude: ', latitude)
-------------------------------------------------------------------
Longitude: -28.1832
Latitude: 7.4263


Здесь важно отметить, что мы вызываем здесь объект response.json (), а не тот, который мы вернули с помощью функции .dumps ().

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

Давайте теперь обратим наше внимание на API Dark Sky, которое требует некоторой настройки, прежде чем мы сможем начать.


APIs 201 - The Dark Sky API и добавление аутентификации.

Давайте зарегистрируем вас!


Для начала нам нужно получить так называемый секретный ключ API. Ключи - это способы аутентификации пользователя без необходимости ввода имени пользователя и пароля. Как таковые, к ним следует относиться безопасно и не распространять их. Чтобы получить свой собственный секретный ключ Dark Sky, зарегистрируйтесь в учетной записи Dark Sky по адресу https://darksky.net/dev/register. Свободный уровень подойдет для экспериментов.

После того, как вы зарегистрируетесь, перейдите на страницу учетной записи https://darksky.net/dev/account, которая предоставит вам ваш ключ API. Запишите этот ключ и сохраните его в секрете.

В рамках бесплатного уровня вы можете совершать до 1000 звонков в день.


Что в Dark Sky API ?


Dark Sky предоставляет исчерпывающий ресурс о том, какие данные включены в их API, к которым вы можете обратиться, посетив: https://darksky.net/dev/docs

Существует два основных типа вызовов: (1) запрос прогноза и (2) запрос машины времени. Первый предоставляет текущую погоду (до следующей недели), а второй предоставляет данные о прошлом и будущем.

Давайте предположим, что мы хотели получить текущие погодные условия (сводка, температура и скорость ветра) для Торонто, Онтарио.

Запросы на прогноз принимаются в следующем формате:

https://api.darksky.net/forecast/[key]/[latitudeitude ,[longitude]

Это означает, что нам нужны три вещи:

1. Наш ключ API

2. Наша широта

3. Наша долгота

Чтобы легко найти широту и долготу, вы можете ввести искомый адрес в Карты Google. Например, я искал CN Tower в Торонто. Возвращенный URL-адрес будет содержать координаты: https://www.google.com/maps/place/CN+Tower/@43.6425701,-79.3892455,17z/

После знака @ сначала идет долгота (43.6425701), а затем широта (-79.3892455).

Давайте напишем код в подробном, но простом для понимания виде. Мы будем использовать f-строки, чтобы сделать код еще проще для чтения. Если вы не знакомы с f-строками, ознакомьтесь с документацией по Python.

Основываясь на документации, мы видим, что общий запрос извлекает больше данных, чем нам нужно. Хотя это и не требуется, мы можем сократить это, используя блок исключения Dark Sky, который уменьшит задержку запроса. Мы будем использовать только текущий блок, поэтому мы исключим все остальные.


secret_key = 'ENTER YOUR KEY HERE'
longitude = -79.3892455
latitude = 43.6425701
exclude = 'minutely, hourly, daily, alerts, flags'
url = f'https://api.darksky.net/forecast/{secret_key}/{latitude},{longitude}?exclude={exclude}'
response = requests.get(url)
dictionary = json.dumps(response.json(), sort_keys = True, indent = 4)
print(dictionary)
------------------------------------------------------------------------------
{
"currently": {
"apparentTemperature": 32.25,
"cloudCover": 1,
"dewPoint": 36.38,
"humidity": 0.95,
"icon": "rain",
"nearestStormDistance": 0,
"ozone": 379.2,
"precipIntensity": 0.076,
"precipIntensityError": 0.03,
"precipProbability": 1,
"precipType": "rain",
"pressure": 998.6,
"summary": "Light Rain",
"temperature": 37.76,
"time": 1583257909,
"uvIndex": 2,
"visibility": 0.245,
"windBearing": 71,
"windGust": 12.67,
"windSpeed": 7.32
},
"latitude": 43.6425701,
"longitude": -79.3892455,
"offset": -5,
"timezone": "America/Toronto"
}


Ранее мы упоминали, что нас будут интересовать текущие условия (в частности, сводка, температура и скорость ветра). Изучив приведенную выше структуру, мы увидим, что мы можем легко получить эти данные, обратившись к парам ключ-значение для этих элементов.

Dark Sky API позволяет вам также устанавливать юниты. В настоящее время в нашем заявлении неясно, в каких единицах находятся извлекаемые нами данные. Давайте будем более точными. Поскольку мы собираем данные для канадского местоположения, давайте уточним их локаль. Документация по Dark Sky API говорит вам, что мы должны установить unit = si.


secret_key = 'ENTER YOUR KEY HERE'
longitude = -79.3892455
latitude = 43.6425701
exclude = 'minutely, hourly, daily, alerts, flags'
url = f'https://api.darksky.net/forecast/{secret_key}/{latitude},{longitude}?units=ca&exclude={exclude}'
response = requests.get(url)
response_json = response.json()
current_summary = response_json['currently']['summary']
current_temperature = response_json['currently']['temperature']
current_wind_speed = response_json['currently']['windSpeed']
print(f'The current temperature in Toronto, Ontario is {current_temperature} degrees Celsius and the wind speed is {current_wind_speed} km/h.')
print(f'The current conditions are: {current_summary}.')
-----------------------------------------------------------------
The current temperature in Toronto, Ontario is 3.22 degrees Celsius and the wind speed is 11.75 km/h.
The current conditions are: Light Rain.


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


Добавление данных в фрейм данных Pandas.


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

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

Давайте немного изучим данные. Мы загрузим данные в соответствии с инструкциями по созданию URL-адреса на веб-сайте и распечатаем данные с помощью функции json.dumps (), описанной выше. Нам нужно будет импортировать те же библиотеки, что и раньше, а также Pandas.


import pandas as pd
import requests
import json
response = requests.get('https://www.quandl.com/api/v3/datasets/FSE/BDT_X')
dictionary = json.dumps(response.json(), sort_keys = True, indent = 4)
print(dictionary)
----------------------------------------------------------------------------
{
"dataset": {
"collapse": null,
"column_index": null,
"column_names": [
"Date",
"Open",
"High",
"Low",
"Close",
"Change",
"Traded Volume",
"Turnover",
"Last Price of the Day",
"Daily Traded Units",
"Daily Turnover"
],
"data": [
[
"2020-02-28",
41.8,
43.45,
41.8,
42.45,
null,
22878.0,
973693.95,
null,
null,
null
],
[
"2020-02-27",
43.0,
45.05,
43.0,
44.2,
null,
20369.0,
894841.4,
null,
null,
null
],
[
"2020-02-26",
44.0,
45.1,
42.5,
44.25,
null,
15533.0,
683974.6,
null,
null,
null
],
...


Данные на самом деле идут очень долго, но здесь они усекаются.

Отсюда видно, что:

Имена столбцов находятся в [‘dataset’][‘column_names’]

Данные находятся в [‘dataset’][‘data’]

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


import pandas as pd
import requests
import json
response = requests.get('https://www.quandl.com/api/v3/datasets/FSE/BDT_X')
response_json = response.json()
df = pd.DataFrame(response_json['dataset']['data'], columns = response_json['dataset']['column_names'])
print(df)
---------------------------------------------------------------------------------------
Date Open High Low Close Change Traded Volume \ ....
0 2020-02-28 41.80 43.45 41.80 42.45 NaN 22878.0
1 2020-02-27 43.00 45.05 43.00 44.20 NaN 20369.0
2 2020-02-26 44.00 45.10 42.50 44.25 NaN 15533.0
3 2020-02-25 46.50 46.85 43.85 44.05 NaN 12435.0
4 2020-02-24 47.65 47.65 45.10 45.95 NaN 19602.0
... ... ... ... ... ... ... ...
5167 2000-01-07 NaN NaN NaN 82.30 NaN 0.0
5168 2000-01-06 NaN NaN NaN 82.30 NaN 0.0
5169 2000-01-05 NaN NaN NaN 82.30 NaN 0.0
5170 2000-01-04 NaN NaN NaN 82.30 NaN 0.0
5171 2000-01-03 NaN NaN NaN 82.30 NaN 0.0


Вывод: что мы узнали о работе с API в Python?


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