YouTube

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


Тип статьиИнструкция
КомпетенцииJupyterLab, Python, Petl, Pandas, YouTube Data API
Необходимые праваДоступ к JupyterLab, доступ к аккаунту Google
Версии компонентовJupyter core - 4.7.1, Petl - 1.7.2 , pandas - 1.2.3, Sqlalchemy - 1.3.23,

google-api-python-client==2.2.0

Статус
БЕТА
Сложность
ЛЕГКО
Полезные ссылкиPetl, Pandas, google-api-python-client, YouTube Data API v3
Дополнительные сведенияОС Ubuntu 18.04


В данной статье рассматривается пример обработки данных, полученных с помощью YouTube Data API. Для примера, мы будем собирать общедоступную статистику канала "Аналитическая платформа Visiology".

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

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

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

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

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

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

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

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

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


Для работы нам понадобятся такие библиотеки, как: google-api-python-client, Petl, Pandas, SQLAlchemy.

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

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

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


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

    from googleapiclient.discovery import build # для получения информации по API
    import petl as etl # для загрузки и обработки данных
    import pandas as pd # для выгрузки таблицы в postgresql
    import sqlalchemy # для создания подключения к базе данных
    import re # регулярные выражение
  3. Укажем YouTube Data API Key, который можно получить следуя документации (в данном примере он изменен на несуществующий). Также создадим объект youtube от YouTube Data, чтобы потом, обращаясь к нему, получать интересующую нас информацию.

    youTubeApiKey = 'BIzaSySxCQe1HesNWugdqXRDXb3LLgdzAv_4bvOtzFsA' # API из аккаунта google 
    youtube = build('youtube', 'v3', developerKey=youTubeApiKey) # Создание объекта, используя YouTube Data API v3
  4. Нужно определить id канала, чтобы потом получить дополнительную информацию.
    Чтобы узнать id канала, достаточно перейти на главную страницу канала и посмотреть в URL.



    Последние символы и есть наш id.

    channel_id = 'UC8LNafdLZNKqs3lbV5xAtNA' # id канала
  5. Далее обратимся к Api YouTube и получим более детальную информацию. Конкретно нас интересует id плейлиста со всеми загруженными видео. Вызовем метод channels().list() нашего объекта youtube. В качестве параметров укажем part='contentDetails' и id = channel_id . Первый параметр означает, что мы хотим получить детальную информацию о канале, а второй - это id нашего канала.

    channel_id = 'UC8LNafdLZNKqs3lbV5xAtNA' # id канала
    content = youtube.channels().list(part='contentDetails', id = channel_id).execute() # получение детальной информации о канале


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



  6. Получим id плейлиста со всеми выгруженными видеозаписями на канале. Они находятся в ключе 'uploads' из словаря выше.

    playlistId = content['items'][0]['contentDetails']['relatedPlaylists']['uploads'] # id плейлиста загруженных видео
  7. Создадим список, в котором будем хранить информацию по всем выгруженным видео.

    allvideos = [] # список с видео
  8.  При запросе информации по видеозаписям в ответе приходит параметр pageToken. Он сообщает токен следующей страницы, в полученном ответе. Воспользуемся им, чтобы останавливать цикл, который будет добавлять информацию о видеозаписях в список.  Укажем переменную nextPage_token = None.

    nextPage_token = None
  9.  Создадим запрос к YouTube Data, воспользовавшись функцией playlistItem().list(), в качестве параметров передадим: playlistId - id плейлиста со всеми выгруженными видеозаписями (его мы определили выше); maxResults = 100 - указывает на максимальное количество тех данных, что мы хотим получить; part = 'snippet' - означает, что мы хотим получить всю информацию о видеозаписях в рамках плейлиста; pageToken = nextPage_token - при первом запросе мы не ссылаемся на следующую страницу, а указываем наш nextPage_token, который равен None. Добавим результат запроса в список allvideos. После первого запроса мы получим токен-ссылку на следующую страницу ответа. Важно понимать, что на каждой странице содержится информация о 50-ти видеозаписях

    res = youtube.playlistItems().list(playlistId = playlistId, maxResults = 100, part = 'snippet', pageToken = nextPage_token).execute()
    allvideos += res['items']
    nextPage_token = res.get('nextPageToken')


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



    Переменная allvideos содержит информацию видео с первой страницы ответа:



  10. Добавим в список все остальные видеозаписи. Т.к. последняя страница ответа не будет иметь токен следующей страницы, мы создадим цикл, который будет добавлять в наш список allvideos информацию об оставшихся видеозаписях пока этот токен существует.

    # добавление оставшихся видео в список
    while nextPage_token is not None:
        res = youtube.playlistItems().list(playlistId = playlistId, maxResults = 100, part = 'snippet', pageToken = nextPage_token).execute()
        allvideos += res['items']
        nextPage_token = res.get('nextPageToken')
  11.  Теперь нужно получить id каждого видео, чтобы в дальнейшем получать его детальную информацию. Мы можем найти его в каждом элементе списка. Воспользуемся Python функцией map(). Она позволит нам применить функцию к каждому элементу нашего списка. Поэтому в качестве параметров мы передаем ей анонимную функцию (лямбда-выражение). Анонимная функция будет получать id каждого элемента списка. Все эти id мы поместим в новый список video_ids.

    video_ids = list(map(lambda x: x['snippet']['resourceId']['videoId'], allvideos)) # получение id видео


    Результат выполнения кода выше:

  12. Создадим список, в который будем добавлять статистику по каждой видеозаписи. Чтобы получить статистику, создадим цикл, в котором будем делать запрос к YouTube Data, пользуясь функцией videos().list(). В качестве параметров передадим: id - id видеозаписи (они берутся у каждой видеозаписи из списка video_ids); part = 'statistics'  - означает, что мы хотим получать статистику по видеозаписи.

    # получение статистики видеозаписей по их id
    stats = []
    for i in range(0, len(video_ids), 40):
        res = youtube.videos().list(id=','.join(video_ids[i:i+40]), part='statistics').execute()
        stats += res['items']


    Полученные данные в переменной stats:

  13.  Чтобы получить информацию о количестве подписчиков канала, создадим запрос к YouTube Data. Воспользуемся функцией channels().list(). В качестве параметров передадим: id - id канала ; part = 'statistics'  - означает, что мы хотим получать статистку канала. 

    channel_stats = youtube.channels().list(part='statistics', id = channel_id).execute() # получение статистики канала

  14. Запишем нужные нам данные в переменную subscriberCount:

    subscriberCount = channel_stats['items'][0]['statistics']['subscriberCount'] # количество подписчиков

  15. В нашем случае, в описании к видеозаписям хранятся ссылки. Мы хотим убрать наименование протокола, чтобы не создавалась гиперссылка в дашборде. Для этого напишем функцию, которая будет искать в тексте слово, начинающееся с 'https' и заменять наименование протокола на пустое значение:



  16. Теперь можно создать список из словарей, в который поместим всю имеющуюся у нас информацию. Одна информация у нас содержится в переменной allvideos, а другая в переменной stats. Поэтому мы создадим цикл, который будет проходит по значениям двух этих переменных и записывать в наш список значения для словаря, который мы укажем.



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



    Теперь у нас есть список словарей, из которых можно с лёгкостью создать таблицу Petl.

  17. Чтобы создать таблицу воспользуемся методом fromdicts() библиотеки Petl.

    table = etl.fromdicts(data) # создание petl таблицы
  18. Добавим в таблицу столбец с количеством подписчиков канала. Для этого мы воспользуемся методом addfield() библиотеки Petl. В качестве параметров, мы передаем методу переменную с имеющейся таблицей, название нового столбца, значение нового столбца.

    table = etl.addfield(table,'subscriberCount', subscriberCount)

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



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

    table.toxlsx('YT_statistics.xlsx', mode='overwrite') # экспорт в Excel файл


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



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

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

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

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

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


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



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

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

    # экспорт в базу данных
    df.to_sql('yt_analytics', engine, index=False, if_exists='replace', dtype={
        'title': sqlalchemy.VARCHAR(100),
        'videoIDs': sqlalchemy.VARCHAR(50),
        'video_description': sqlalchemy.Text(),
        'publishedDate': sqlalchemy.Date(),
        'liked': sqlalchemy.Integer(),
        'disliked': sqlalchemy.Integer(),
        'views': sqlalchemy.Integer(),
        'comment': sqlalchemy.Integer(),
        'subscriberCount': sqlalchemy.Integer()
    })

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

    Excel таблица:


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

    1:



    2:


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

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


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