Сохраняем комментарии youtube в csv
- суббота, 3 июля 2021 г. в 00:32:31
Как-то на одном youtube канале, устроили розыгрыш среди комментаторов.
Условием было угадать цену закрытия акций хотя бы одной из трёх конкретных компаний.
Мне стало интересно собрать статистику за какие цены пользователи голосовали больше других и сработал ли "коллективный разум", когда пусть каждый отдельно взятый голос был далёк от истины, но среднее значение голосов внезапно попадало в точку.
Плюс задача сбора статистики усложнялась тем, что комментарии написаны в единое текстовое поле, а не в форму, где все значения на своих местах и нужного типа.
Заспойлерю: распарсить комментарии оказалось самой трудоёмкой задачей, потому что не было даже единой схемы ответа (ок была превалирующая, но далеко не единственная):
одни писали сначала название компании потом цену, другие -- наоборот цену, потом компанию (кое-кто писал название, много вводных слов обосновывающих его мысли и потом цену)
Где-то было название, где-то тикер
Местами текст был на английском, местами на русском
Дробные части отделяли и точками и запятыми
Встречались и опечатки в несколько букв (в одном слове)
Многие сокращали название до двух букв, сочетание которых очевидно встречалась и в обычных комментариях, не связанных с конкурсом
Были и жаргонные названия компаний (Бумер вместо BMW), и наоборот полные (Bayerische Motoren Werke)
Но призёрами в борьбе с парсингом стали люди, писавшие в словах Tesla и BMW - русскую букву "т" и русскую "в" в начале слова, а дописывавшие его английскими буквами
(последнее заметил по чистой случайности просматривая json содержимое, когда латиница идёт буквами, а весь юникод заменяется слешами с кодами)
Во-первых, не все хотят платить за то, что можно получить бесплатно.
Во-вторых, не у всех хорошо с английским, да и зачем курить длинные мануалы, если задача узкая и односложная.
В-третьих, никакой похожей инструкции на первой странице поиска не нашлось, думаю это нужно исправить.
Чтобы инструкция была более гибкой и её можно было использовать, даже если что-то изменится в одном из шагов, в каждом оставлю источники.
Получите ключ для работы с youtube API (источник)
Возьмитие ваш гугл-аккаунт и создайте проект по ссылке https://console.developers.google.com/
На странице разрешений https://console.developers.google.com/apis/credentials
Создайте новый API ключ
На главной https://console.cloud.google.com/apis/dashboard
Перейдите к странице включения сервисов для API
Найдите YouTube Data API v3
Включите его
Получите библиотеку google-api-python-client (источник)
Возьмите python
Выполните команду
pip.exe install google-api-python-client
Запустите скрипт
Возьмите редактор, например visual studio code
Создайте новый 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 - в случае их равенства комментарий корневой, иначе реплай.