Если вы новичок в области науки о данных, вы часто будете работать в курсах и учебных пособиях с файлами .csv, которые легко читать в фреймах данных Pandas. Однако на практике вам часто требуется доступ к API и получение данных в формате Json. Эти данные часто содержат вложенные списки и словари.

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

Чтобы следовать этому руководству, необходимы базовые знания Python, а также знание пакета pandas. Предполагается, что вы знаете, что такое API.

Запрос API

Для начала вам нужно посмотреть API-документацию и узнать URL-адрес API-интерфейса и конечных точек. Затем нам нужно указать, какой тип фактов мы хотим получить. В этом примере мы запрашиваем конечную точку:

GET /facts/random

базовый URL всех конечных точек - https://cat-fact.herokuapp.com..

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

Теперь приступим к созданию запроса на Python:

import requests
import pandas as pd
import json
import pprint
import seaborn as sns
import matplotlib.pyplot as plt

Сначала нам нужно импортировать необходимые пакеты. В этом руководстве мы используем запросы для доступа к API через HTTP-запрос. Pandas для чтения данных JSON в DataFrame и выполнения исследовательского анализа. Seaborn и matplotlib используются для визуализации данных.

base_url = "https://cat-fact.herokuapp.com"
facts = "/facts/random?animal_type=cat&amount=500"

Теперь мы сохраняем базовый URL и используемую конечную точку в переменных.

first_response = requests.get(base_url+facts)
response_list=first_response.json()

Чтобы получить данные в виде вывода Json, вы можете использовать пакет запросов. Для этого мы вызываем метод request.get с базовым URL и конечной точкой и сохраняем возвращенные значения в переменной first_response. Затем вывод Json можно проанализировать с помощью метода .json () и сохранить в списке. Печать response_list показывает нам структуру полученных данных:

[{'used': False,
  'source': 'api',
  'type': 'cat',
  'deleted': False,
  '_id': '591f97e88dec2e14e3c20b06',
  '__v': 0,
  'text': 'A female Amur leopard gives birth to one to four cubs in each litter.',
  'updatedAt': '2020-08-23T20:20:01.611Z',
  'createdAt': '2018-05-16T20:20:03.145Z',
  'status': {'verified': True, 'sentCount': 1},
  'user': '5a9ac18c7478810ea6c06381'},
 {'used': False,
  'source': 'user',
  'type': 'cat',
  'deleted': False,
  '_id': '5c87d03dec1e5c0aa37e0a6b',
  'user': '5a9ac18c7478810ea6c06381',
  'text': 'On October 24, 1963, a tuxedo cat named Félicette entered outer space aboard a French Véronique AG1 rocket and made feline history. Félicette returned from the 15-minute trip in once piece and earned the praise of French scientists, who said she made "a valuable contribution to research.".',
  'createdAt': '2019-03-12T15:29:01.505Z',
  'updatedAt': '2020-08-23T20:20:01.611Z',
  '__v': 0,
  'status': {'verified': True, 'sentCount': 1}},
 {'used': False,
  'source': 'api',
  'type': 'cat',
  'deleted': False,
  '_id': '591f98783b90f7150a19c1b5',
  '__v': 0,
  'text': "Cats have 32 muscles that control the outer ear (compared to human's 6 muscles each). A cat can rotate its ears independently 180 degrees, and can turn in the direction of sound 10 times faster than those of the best watchdog.",
  'updatedAt': '2020-08-23T20:20:01.611Z',
  'createdAt': '2018-01-04T01:10:54.673Z',
  'status': {'verified': True, 'sentCount': 1},
  'user': '5a9ac18c7478810ea6c06381'}
...
]

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

Возможно, существует бесчисленное множество способов выполнить этот шаг. Это один из возможных способов получить значения из подклассов.

data=[]
for response in response_list:  
    data.append({
        "used": response.get('used'),
        "source": response.get('source'),
        "text": response.get('text'),
        "updatedAt": response.get('updatedAt'),
        "createdAt": response.get('createdAt'),
        "user": response.get('user')
        
    })

Затем мы просто преобразуем наш список в фрейм данных pandas с помощью метода pd.Dataframe.

catfacts_df=pd.DataFrame(data)
catfacts_df.head()

Теперь, когда мы успешно импортировали данные в фреймворк pandas, мы можем получить доступ к большему количеству данных через API. Было бы интересно узнать, какой пользователь добавил катфакты. Для этого мы должны получить конечную точку «GET / fact?» снова и объедините фреймы данных о пользователях с данными catfacts_df. Здесь вы должны следить за тем, чтобы не получить повторяющиеся пользовательские значения. Мы хотим использовать только список с именем пользователя и идентификатором пользователя и использовать эту информацию для объединения двух фреймов данных. Но, получая данные из фактов конечной точки, мы должны удалить повторяющиеся строки на основе идентификатора пользователя. Таким образом мы получаем список, в который каждый пользователь включен один раз.

Мы также должны отметить, что необходимо проверить, является ли точка данных полной и не имеет ли пропущенных значений. Мы делаем это с условием if. Таким образом, мы вставляем в список только полные точки данных, иначе код вернет ошибку. После создания DataFrame с данными и удаления повторяющихся значений на основе столбца «пользователь» мы также сбрасываем индекс.

user_facts="/facts?"
user_response=requests.get(base_url+user_facts)
user_list=user_response.json()
users=[]
for response in user_list.values():
    for user in response:
        if user.get('user'):
            users.append({
              "user": user.get('user').get('_id'),
              "firstname":user.get('user').get('name').get('first'), 
              "lastname":user.get('user').get('name').get('last')
})
userfacts_df= pd.DataFrame(users)
userfacts_df = userfacts_df.drop_duplicates(subset = ["user"])
userfacts_df.reset_index(inplace=True,drop=True)
userfacts_df.tail()

Печать DataFrame показывает, что существует 83 уникальных отправителя катфактов.

Теперь следующий важный шаг - объединить оба фрейма данных в один. Для этого мы используем метод .merge и указываем, что он должен быть объединен в левом наборе данных (catfacts_df) в столбце «пользователь».

df=catfacts_df.merge(userfacts_df, how='left', on= "user")

После объединения обоих фреймов данных важно подтвердить, что слияние было правильным.

Прежде чем мы продолжим визуализацию, имеет смысл вставить уже написанный код в четко организованную функцию. Здесь мы также можем установить параметр «количество», чтобы получить определенное количество катфактов.

def get_cat_facts(amount):
    base_url="https://cat-fact.herokuapp.com"
    
    # get cat facts
    response=requests.get(base_url+ "/facts/random?animal_type=cat&amount=" + str(amount))
    response_json=response.json()
    
    data=[]
    for response in response_json:  
        data.append({
            "used": response.get('used'),
            "source": response.get('source'),
            "text": response.get('text'),
            "updatedAt": response.get('updatedAt'),
            "createdAt": response.get('createdAt'),
            "user": response.get('user')
})
    
    
    #create catdf
    catfacts_df=pd.DataFrame(data) 
    
    # get user data
    
    user_response=requests.get(base_url+ "/facts?")
    user_json=user_response.json()
    
    users=[]
    for response in user_json.values():
        for user in response:
            if user.get('user'):
users.append({
                    "user": user.get('user').get('_id'),
                    "firstname":user.get('user').get('name').get('first'), 
                    "lastname":user.get('user').get('name').get('last')
})
    #create userdf
    userfacts_df=pd.DataFrame(users) 
    userfacts_df = userfacts_df.drop_duplicates(subset = ["user"])
    #joining both datframes
    df=catfacts_df.merge(userfacts_df, how='left', on= "user")
    
    return df
cat_facts_df = get_cat_facts(amount=500)

На последнем этапе мы можем визуализировать данные. Здесь я просто визуализировал, сколько фактов отправил пользователь.

# catfacts per user
agg_user_df
=cat_facts_df.groupby(['user', 'firstname', 'lastname']).agg({
    "text": 'count'
})
top_ten=agg_user_df.nlargest(10, 'text')
bar_plot=sns.barplot(x = 'lastname', y = 'text', data = top_ten,
            palette = 'hls',  
            capsize = 0.05,             
            saturation = 8,             
            errcolor = 'gray', errwidth = 2,  
            ci = 'sd'
            
            )
bar_plot.set_title('Facts by User')
bar_plot.set_ylabel('Amount Cat Facts')
bar_plot.set_xlabel('Lastname')
plt.xticks(rotation=45)
plt.show()

В репозитории GitHub вы можете получить весь код. Я надеюсь, что вам понравился этот учебник, и я надеюсь, что он поможет вам при работе с API.