Facebook

Ноутбук, используемый в примере:
Facebook.ipynb


Тип статьиИнструкция
КомпетенцииJupyterLab, Python, Petl, Pandas, Facebook Graph API
Необходимые праваДоступ к JupyterLab, доступ к аккаунту Facebook
Версии компонентов

Jupyter core - 4.7.1, Petl - 1.7.2, pandas - 1.2.3, Sqlalchemy - 1.3.23,

facebook-sdk - 3.1.0

Статус
ЧЕРНОВИК
СложностьНадо попотеть
Полезные ссылкиPetl, Pandas, facebook-sdk, Facebook Graph API.
Дополнительные сведенияОС Ubuntu 18.04

В данной статье рассматривается пример обработки данных, полученных с помощью Facebook Graph API. Для удобства работы с API будет использована Python библиотека Facebook Python SDK

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

Функционал обеих библиотек схож, и вы можете использовать ту, что вам больше нравится.


Целью этого задания является получение данных с помощью Facebook Graph API для выгрузки их в платформу и построения дашборда.
Пример не является шаблонным: в каждом случае задачи разнятся, и работать с данными придется по-другому.

Вот особенности данного кейса:

  • Количество получаемых данных небольшое - порядка 80 строк, но для демонстрации правильного подхода все выгруженные и обработанные данные сохраняются в Excel файл и базу данных PostgreSQL. Для загрузки данных в платформу вы можете использовать любой из вариантов. Когда получаемых данных много - правильнее всего использовать запись в базу данных.

Здесь не рассматривается:

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

  • Для дальнейшей загрузки в платформу можно воспользоваться стандартными средствами в платформе: “создание загрузчика” и “планы загрузки”. Всё описано в разделе документации (ссылка для версии 2.20):
    Загрузка данных и формирование структуры в аналитической базе данных ViQube

  • Подробности работы подключенных Python библиотек. Это необходимо изучать отдельно.


Для работы нам понадобятся такие библиотеки, как: Facebook Python SDK, Petl, Pandas, SQLAlchemy.

Если они у вас не установлены, то вы можете воспользоваться статьей по установке библиотек:

Установка Python библиотек

Теперь можно приступать к работе в JupyterLab.


  1. Создаем ноутбук с названием Facebook.
  2. Первым блоком подключаем все необходимые нам для работы Python библиотеки.

    import facebook # для подключения к Facebook Graph API
    
    import petl as etl # для загрузки и обработки данных
    import pandas as pd # для удобной работы с датой и выгрузки таблицы в postgresql
    
    import datetime as dt # для установления даты
    import sqlalchemy # для создания подключения к базе данных
  3. Укажем в переменную user_token токен аутентификации, который можно получить, следуя инструкции Использование API Graph.

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

    user_token = {your_user_token}

    Где {your_user_token} - ваш токен аутентификации.

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

    graph = facebook.GraphAPI(access_token=user_token, version="3.0")
    pages_data = graph.get_object("/me/accounts")


    Переменная pages_data содержит в себе следующую информацию:



  5. Из полученного ответа, мы можем записать в переменные токен страницы и ID страницы.

    permanent_page_token = pages_data['data'][0]['access_token']
    page_id = pages_data['data'][0]['id']
  6. Теперь мы можем получать интересующие нас данные. Для начала запросим количество людей, которые видели любой контент связанный с нашей страницей, с разбивкой по стране.

    Воспользуемся методом get_connection() библиотеки facebook-sdk.

    В качестве параметров мы указываем:
    access_token=permanent_page_token - полученный выше токен страницы;
    id=page_id - полученный выше id страницы; 
    connection_name='insights' - название подключения, в данном случае это статистика страницы;
    metric='page_impressions_by_country_unique' - интересующая нас метрика;
    date_preset='this_year' - диапазон дат, за который берется отчёт;
    period='day' - период агрегации дат;
    show_description_from_api_doc=True - добавляет в конце ответа информацию по запросу из документации.

    content_views_by_country = graph.get_connections(access_token=permanent_page_token,
                                             id=page_id,
                                             connection_name='insights',
                                             metric='page_impressions_by_country_unique',
                                             date_preset='this_year',
                                             period='day',
                                             show_description_from_api_doc=True)


    Переменная content_views_by_country содержит в себе следующую информацию:

  7. Создадим фиксированный словарь с кодами стран и их расшифровкой, они понадобятся для дальнейшей работы с таблицей. Если вы хотите получать коды и названия стран динамически (чтобы он всегда был актуален), то можете воспользоваться API REST Countries или другим доступным в Интернете методом.

    codes = {
        'AD': 'Andorra',
        'AE': 'United Arab Emirates',
        ...
        'ZW': 'Zimbabwe',
        'ZZ': 'Unknown or unspecified country',
    }
  8. Чтобы сформировать правильную таблицу Petl, нужно изменить структуру полученного ответа. Мы создадим список, в который будем добавлять дату, код страны и значение. Пройдёмся по каждому элементу списка content_views_by_country['data'][0]['values'].
    Элементом является словарь с двумя ключами - value, end_time. Значением ключа value является словарь, внутри которого ключи - это коды стран, а значения - это количество людей из этой страны.
    Внутри первого цикла создадим еще один, который будет проходить по значениям словаря value. Для каждого элемента в этом цикле мы преобразуем дату в нужный нам формат, а затем добавим в созданный ранее список все данные.

    rows = []
    for entrance in content_views_by_country['data'][0]['values']:
        for region, value in entrance['value'].items():
            date = dt.datetime.strptime(entrance['end_time'].split('T')[0], '%Y-%m-%d').strftime('%Y-%m-%d') # преобразование даты
            rows.append([date, region, value])


    Переменная rows содержит следующую информацию:

  9.  Создадим таблицу Petl, используя метод setheader(). В качестве параметров передадим ему наш список с данными и список с названиями столбцов, которые мы видеть у нашей таблицы.

    table1 = etl.setheader(rows, ['content_views_by_country_date', 'country', 'content_views_by_country_values'])


    Переменная table1 содержит следующие данные:

  10. Для более информативного отображения мы добавим в таблицу столбец Country, в который поместим расшифровку кодов стран из столбца country. Воспользуемся методом addfield() библиотеки Petl. Этот метод в качестве параметров принимает переменную, из которой строится таблица (нашем случае это переменная table1), название нового столбца, и значение, которым будет заполнен столбец. В качестве этого значения можно передать анонимную функцию (лямбда выражение). У нашей функции в качестве переменной x - код страны. Мы будем использовать словарный метод get(), передадим ему переменную x. Функция будет искать в нашем словаре codes ключи из столбца country и возвращать значения по этим ключам. Эти значения мы и запишем в новый столбец Country.

    table1 = etl.addfield(table1, 'Country', lambda x: codes.get(x['country']))


    В таблице появился новый солбец:

  11. По той же схеме, получим приблизительное число людей, которые видели любой контент связанный с нашей страницей, с разбивкой по полу и гендеру. 
    Воспользуемся тем же методом get_connection() библиотеки facebook-sdk. Передадим этому методу те же параметры, за исключением поля metric. Полю metric мы укажем значение page_impressions_by_age_gender_unique.

    content_views_by_age_gender = graph.get_connections(access_token=permanent_page_token,
                                             id=page_id,
                                             connection_name='insights',
                                             metric='page_impressions_by_age_gender_unique',
                                             date_preset='this_year',
                                             period='day',
                                             show_description_from_api_doc=True)


    Переменная content_views_by_age_gender содержит в себе следующую информацию:



  12. Также запишем данные в пустой список. Ключ гендера и возраста мы разделим на две разных строки. Для этого воспользуемся Python методом split(). В качестве разделителя укажем символ точки. Метод вернет нам список из двух элементов ( буква гендера и возраст). Затем мы соединим эти элементы, используя Python метод join(). В качестве соединителя укажем символ пробела.

    rows_by_age_gender = []
    for entrance in content_views_by_age_gender['data'][0]['values']:
        for gender, value in entrance['value'].items():
            date = dt.datetime.strptime(entrance['end_time'].split('T')[0], '%Y-%m-%d').strftime('%Y-%m-%d')
            rows_by_age_gender.append([date, ' '.join(gender.split('.')), value])


    Список rows_by_age_gender содержит следующие данные:



  13. Разделим элемент с полом и возрастом на два элемента. Для этого воспользуемся следующей конструкцией:

    new_rows_by_age_gender = []for row in rows_by_age_gender:
         new_rows_by_age_gender.append(([*row[:1], *row[1].split(), *row[2:]]))


    Список new_rows_by_age_gender содержит следующие данные:



  14. Создадим вторую таблицу, по аналогии с первой.

    table2 = etl.setheader(new_rows_by_age_gender, ['content_views_by_age_gender_date', 'gender', 'age', 'content_views_by_age_gender_value'])


  15. Для удобства расшифруем пол пользователей. Сначала создадим словарь с расшифровкой.

    genders = {
        'M': 'Мужчины',
        'F': 'Женщины',
        'U': 'Неопределен'
    }
  16. Так же, как и ранее добавим новый столбец.

    table2 = etl.addfield(table2, 'Gender', lambda x: genders.get(x['gender']))


  17. Запросим число людей, на экране которых отображались любые публикации вашей Страницы. Публикациями считаются статусы, фото, ссылки, видео и т. п. Не забываем изменить метрику на page_impressions_unique .

    page_publications_views = graph.get_connections(access_token=permanent_page_token,
                                             id=page_id,
                                             connection_name='insights',
                                             metric='page_impressions_unique',
                                             date_preset='this_year',
                                             period='day',
                                             show_description_from_api_doc=True)


  18. Добавим данные в список.

    publications_views = []
    for entrance in page_publications_views['data'][0]['values']:
        date = dt.datetime.strptime(entrance['end_time'].split('T')[0], '%Y-%m-%d').strftime('%Y-%m-%d')
        publications_views.append([date, entrance['value']])
  19. Создадим третью таблицу.

    table3 = etl.setheader(publications_views, ['publications_views_date', 'publications_views_value'])


  20. Также получим число просмотров пользователями профиля нашей страницы. Опять-таки, не забывая изменить поле метрики. В этом случае нам понадобится метрика "page_views_total".

    page_views_total = graph.get_connections(access_token=permanent_page_token,
                                             id=page_id,
                                             connection_name='insights',
                                             metric='page_views_total',
                                             date_preset='this_year',
                                             period='day',
                                             show_description_from_api_doc=True)


  21. Создадим список из полученных данных, чтобы потом создать таблицу.

    page_view = []
    for entrance in page_views_total['data'][0]['values']:
        date = dt.datetime.strptime(entrance['end_time'].split('T')[0], '%Y-%m-%d').strftime('%Y-%m-%d')
        page_view.append([date, entrance['value']])


  22. Теперь мы можем сформировать четвертую таблицу.

    table4 = etl.setheader(page_view, ['page_views_date', 'page_views_value'])




  23. Теперь объединим все имеющиеся у нас таблицы в одну. Для этого мы воспользуемся методом annex() блиблиотеки Petl. В качестве параметров передадим этому методу все наши ранее сформированные таблицы.

    table = etl.annex(table1, table2, table3, table4)


    Получим такую таблицу:



  24. Удалим два ненужных столбца "country" и "gender". Для этого воспользуемся методом cutout() блиблиотеки Petl.

    table = table.cutout('country', 'gender')
  25. Мы можем экспортировать нашу таблицу в Excel файл для дальнейшей загрузки на платформу. Для этого воспользуемся методом toxlsx() библиотеки Petl. В качестве параметров передаем методу название Excel файла и флаг mode='overwrite', который указывает, что файл будет перезаписываться при повторном запуске кода.

    table.toxlsx('facebook.xlsx', write_header=True, mode='overwrite')

    Мы получили Excel таблицу, которую можно загружать на платформу:



  26. Помимо экспорта а Excel продемонстрируем подход с сохранением данных в PostgreSQL. Установим подключение к базе данных с помощью метода create_engine() библиотеки Sqlachemy.

    engine = sqlalchemy.create_engine('postgresql://{user}:{user_password}@{url}:{port}/{database_name}') # подключение к базе данных	

    Где {user} - имя пользователя базы данных, {user_password} - пароль, {url} - адрес базы данных, {port} - порт, {database_name} - название базы данных, в которой будет создана таблица.

  27. Далее создадим объект DataFrame библиотеки Pandas из нашей таблицы Petl. Воспользуемся методом DataFrame() и укажем ему, что названия колонок - это table[0], а значения - это срез от первого элемента таблицы Petl до последнего table[1:].

    df = pd.DataFrame(columns=table[0], data=table[1:]) # создание DataFrame из petl-таблицы


    Получим таблицу Pandas:


  28. Теперь экспортируем таблицу в базу данных PostgreSQL с помощью метода to_sql() библиотеки Pandas. В параметрах передаем название таблицы, переменную подключения engine, которую определили выше, флаги index=False и if_exists='replace', и словарь с типами данных для столбцов. Флаг index=False говорит, что не нужно создавать столбец с индексами. Флаг if_exists='replace' указывает, что таблицу нужно перезаписать, если она уже существует. В словаре dtype мы указываем название столбца в качестве ключа, а в качестве значения указывается тип данных библиотеки Sqlalchemy и его длина. Типы данных можно посмотреть тут.

    Например, для столбца ‘Country’ мы укажем тип данных VARCHAR с длинной 50. Указывается такая длина, т.к. в нашем примере название страны не будет длиннее пятидесяти символов.

    # экспорт в базу данных
    df.to_sql('facebook', engine, index=False, if_exists='replace', dtype={
        'content_views_by_country_date': sqlalchemy.Date(),
        'content_views_by_country_values': sqlalchemy.Integer(),
        'Country': sqlalchemy.VARCHAR(50),
        'content_views_by_age_gender_date': sqlalchemy.Date(),
        'age' : sqlalchemy.VARCHAR(10),
        'content_views_by_age_gender_value': sqlalchemy.Integer(),
        'Gender': sqlalchemy.VARCHAR(15),
        'publications_views_date': sqlalchemy.Date(),
        'publications_views_value': sqlalchemy.Integer(),
        'page_views_date': sqlalchemy.Date(),
        'page_views_value': sqlalchemy.Integer(),
    })

    Мы получили таблицу Excel и таблицу в базе данных PostgreSQL.

    Excel таблица:



    Таблица в базе данных:

    1:



    2:



    Где 1 - это типы данных столбцов, 2 - данные таблицы.

    Так выглядит дашборд, построенный из этих данных:



    Полученные файлы можно брать и загружать в платформу через стандартный загрузчик. На этом работа в ViXtract завершена.🥳