Сохраняем комментарии youtube в csv

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Предыстория

Как-то на одном youtube канале, устроили розыгрыш среди комментаторов.

Условием было угадать цену закрытия акций хотя бы одной из трёх конкретных компаний.

Мне стало интересно собрать статистику за какие цены пользователи голосовали больше других и сработал ли "коллективный разум", когда пусть каждый отдельно взятый голос был далёк от истины, но среднее значение голосов внезапно попадало в точку.

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

Заспойлерю: распарсить комментарии оказалось самой трудоёмкой задачей, потому что не было даже единой схемы ответа (ок была превалирующая, но далеко не единственная):

  • одни писали сначала название компании потом цену, другие -- наоборот цену, потом компанию (кое-кто писал название, много вводных слов обосновывающих его мысли и потом цену)

  • Где-то было название, где-то тикер

  • Местами текст был на английском, местами на русском

  • Дробные части отделяли и точками и запятыми

  • Встречались и опечатки в несколько букв (в одном слове)

  • Многие сокращали название до двух букв, сочетание которых очевидно встречалась и в обычных комментариях, не связанных с конкурсом

  • Были и жаргонные названия компаний (Бумер вместо BMW), и наоборот полные (Bayerische Motoren Werke)

  • Но призёрами в борьбе с парсингом стали люди, писавшие в словах Tesla и BMW - русскую букву "т" и русскую "в" в начале слова, а дописывавшие его английскими буквами ​

    (последнее заметил по чистой случайности просматривая json содержимое, когда латиница идёт буквами, а весь юникод заменяется слешами с кодами)

Для чего эта статья? Ведь есть платные парсеры / документация на Yotube API

Во-первых, не все хотят платить за то, что можно получить бесплатно.

Во-вторых, не у всех хорошо с английским, да и зачем курить длинные мануалы, если задача узкая и односложная.

В-третьих, никакой похожей инструкции на первой странице поиска не нашлось, думаю это нужно исправить.

Чтобы инструкция была более гибкой и её можно было использовать, даже если что-то изменится в одном из шагов, в каждом оставлю источники.

  1. Получите ключ для работы с youtube API (источник)

    1. Возьмитие ваш гугл-аккаунт и создайте проект по ссылке https://console.developers.google.com/

    2. На странице разрешений https://console.developers.google.com/apis/credentials

      Создайте новый API ключ

      (Сохраните его, чтобы потом не искать)
      (Сохраните его, чтобы потом не искать)
    3. На главной https://console.cloud.google.com/apis/dashboard

      Перейдите к странице включения сервисов для API

    4. Найдите YouTube Data API v3

    5. Включите его

  2. Получите библиотеку google-api-python-client (источник)

    1. Возьмите python

    2. Выполните команду

      pip.exe install google-api-python-client

  3. Запустите скрипт

    1. Возьмите редактор, например visual studio code

    2. Создайте новый python файл и вставьте в него следующий код

      Всё что вам нужно в нём поправить для старта это

      • DEVELOPER_KEY -- получен в первом пункте

      • VIDEO_ID -- берётся из ссылки на видео, например в ссылке https://youtu.be/9b4-G-czN5Y нас интересует 9b4-G-czN5Y

# -*- coding: utf-8 -*-

import os
import googleapiclient.discovery
import csv

DEVELOPER_KEY = "AIzaSyB7oKxIsd4690TibZHZPaTLzw7nqzgrr4k"
VIDEO_ID = "9b4-G-czN5Y"

# Функция для скачивания корневых комментариев
def youtube(nextPageToken=None):
    # Disable OAuthlib's HTTPS verification when running locally.
    # *DO NOT* leave this option enabled in production.
    os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"

    api_service_name = "youtube"
    api_version = "v3"    

    youtube = googleapiclient.discovery.build(
        api_service_name, api_version, developerKey = DEVELOPER_KEY)

    request = youtube.commentThreads().list(
        part="id,snippet",
        maxResults=100,
        pageToken=nextPageToken,
        videoId=VIDEO_ID
    )
    response = request.execute()
    return response

# Функция для скачивания реплаев на комментарии
def youtubechild(NextParentId, nextPageToken=None):
    # Disable OAuthlib's HTTPS verification when running locally.
    # *DO NOT* leave this option enabled in production.
    os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"

    api_service_name = "youtube"
    api_version = "v3"

    youtube = googleapiclient.discovery.build(
        api_service_name, api_version, developerKey = DEVELOPER_KEY)

    request = youtube.comments().list(
        part="id,snippet",
        maxResults=100,
	pageToken=nextPageToken,
        parentId=NextParentId
    )
    response = request.execute()
    return response

# Главная функция
def main():
    # Скачиваем комментарии
    print('download comments')
    response = youtube()
    items = response.get("items")
    nextPageToken = response.get("nextPageToken") # скачивается порциями, на каждую следующую выдаётся указатель
    i=1
    while nextPageToken is not None:
        print(str(i*100)) # показываем какая сотня комментариев сейчас скачивается
        response = youtube(nextPageToken)
        nextPageToken = response.get("nextPageToken")
        items = items + response.get("items")
        i+=1

    print(len(items)) # Отображаем количество скачаных комментариев

    # Скачиваем реплаи на комментарии
    print('download replies')
    replies = []
    for line in items: # Проходим по корневым комментам
        if line.get("snippet").get("totalReplyCount") > 0: # если есть реплаи
            print(line.get("snippet").get("totalReplyCount")) # показываем сколько реплаев будет подгружено
            response = youtubechild(line.get("snippet").get("topLevelComment").get("id"))
            replies = replies + response.get("items")
            nextPageToken = response.get("nextPageToken")
            i=1
            while nextPageToken is not None: # догружаем реплаи, если есть ещё порции
                response = youtubechild(line.get("snippet").get("topLevelComment").get("id"), nextPageToken)
                nextPageToken = response.get("nextPageToken")
                replies = replies + response.get("items")
                i+=1

    print(len(replies)) # Отображаем количество скачаных реплаев

    # Сохраняем комментарии и реплаи на них в файл csv
    print("Open csv file")
    with open('youtuberesults.csv', 'w', encoding="utf-8") as csv_file:  #конструкция with, чтобы файл закрылся автоматом после всех команд
        writer = csv.writer(csv_file, quoting=csv.QUOTE_ALL, lineterminator='\r') # использовал двойные кавычки и разделитель запятую, такой формат отлично открывается через LibreOffice Calc

        # Заголовки столбцов
        row = [
              'etag'
            , 'parentid'
            , 'id'
            , 'textDisplay'
            , 'textOriginal'
            , 'authorDisplayName'
            , 'authorProfileImageUrl'
            , 'authorChannelUrl'
            , 'authorChannelId'
            , 'likeCount'
            , 'publishedAt'
            , 'updatedAt'
        ]
        print("Start write in csv")  
        writer.writerow(row) # Записываем заголовки в файл
    
        # Сохраняем комментарии
        print("Write comments in csv")  
        for line in items:
            topLevelComment = line.get("snippet").get("topLevelComment")
            # бывает, что у пользователя нет канала, поэтому для него отдельная конструкция
            if topLevelComment.get('snippet').get('authorChannelId') is not None:
                authorChannelId = topLevelComment.get('snippet').get('authorChannelId').get('value')
            else:
                authorChannelId = ''
            row = [
                  topLevelComment.get('etag')
                , topLevelComment.get('id')
                , topLevelComment.get('id')
                , topLevelComment.get('snippet').get('textDisplay')
                , topLevelComment.get('snippet').get('textOriginal')
                , topLevelComment.get('snippet').get('authorDisplayName')
                , topLevelComment.get('snippet').get('authorProfileImageUrl')
                , topLevelComment.get('snippet').get('authorChannelUrl')
                , authorChannelId
                , topLevelComment.get('snippet').get('likeCount')
                , topLevelComment.get('snippet').get('publishedAt')
                , topLevelComment.get('snippet').get('updatedAt')
            ]
            writer.writerow(row)

        # Сохраняем реплаи
        print("Write replies in csv")  
        for line in replies:
            # бывает, что у пользователя нет канала, поэтому для него отдельная конструкция
            if line.get('snippet').get('authorChannelId') is not None:
                authorChannelId = line.get('snippet').get('authorChannelId').get('value')
            else:
                authorChannelId = ''
            row = [
                  line.get('etag')
                , line.get('snippet').get('parentId')
                , line.get('id')
                , line.get('snippet').get('textDisplay')
                , line.get('snippet').get('textOriginal')
                , line.get('snippet').get('authorDisplayName')
                , line.get('snippet').get('authorProfileImageUrl')
                , line.get('snippet').get('authorChannelUrl')
                , authorChannelId
                , line.get('snippet').get('likeCount')
                , line.get('snippet').get('publishedAt')
                , line.get('snippet').get('updatedAt')
            ]
            writer.writerow(row)
        
    print("done")  

if __name__ == "__main__":
    main()

В полученной таблице все поля, которые доступны по YouTube API.

Созданный csv отлично открывается в LibreOffice Calc.

Используются двойные кавычки и разделитель запятая, кодировка UTF-8. 

Если нужно отличить корневой комментарий от реплая можно добавить столбец с сравнением parentid с id - в случае их равенства комментарий корневой, иначе реплай.

Источник: https://habr.com/ru/post/565812/


Интересные статьи

Интересные статьи

Компания «Деловой разговор» — Титановый партнер 3СХ — осуществила расширенную интеграцию IP-АТС 3CX с Битрикс 24. Ранее уже существовали отдельные модули, решающие конкретные задачи, напр...
В этой статье мы рассмотрим, как система управления 1С-Битрикс справляется с большими нагрузками. Данный вопрос особенно актуален сегодня, когда электронная торговля начинает конкурировать по обороту ...
На днях встала задача получения сообщений из стрима youtube. Статей по этому поводу не нашел, а есть лишь офф. документация гугл. С ней я разобрался (надеюсь) и готов поделиться с вами опытом. ...
Но если для интернет-магазина, разработанного 3–4 года назад «современные» ошибки вполне простительны потому что перед разработчиками «в те далекие времена» не стояло таких задач, то в магазинах, сдел...