目的
youtubeの切り抜き動画を作成するために、
チャットのデータがテキストファイルとして手元にあったら便利だと思ったので作成しました。
需要があるかわかりませんが、いろいろ躓いた箇所があったので残しておきます。
こちらの記事をもとに作成しました。
勝手にリンクはってるので、怒られたら消します。
http://watagassy.hatenablog.com/entry/2018/10/08/132939
http://watagassy.hatenablog.com/entry/2018/10/06/002628
https://teratail.com/questions/276731?link=qa_related_pc
https://teratail.com/questions/263421?link=qa_related_pc
必要環境
python 3
・pip でインストールするやつ
BeautifulSoup
requests
requests_html
lxml
コード
from bs4 import BeautifulSoup
import json
import requests
import requests_html
from urllib.parse import urlparse, parse_qs
import sys
target_url = input()
dict_str = ""
next_url = ""
comment_data = []
session = requests_html.HTMLSession()
headers = {'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'}
# まず動画ページにrequestsを実行しhtmlソースを手に入れてlive_chat_replayの先頭のurlを入手
resp = session.get(target_url)
resp.html.render(sleep=3)
for iframe in resp.html.find("iframe"):
if("live_chat_replay" in iframe.attrs["src"]):
next_url= "".join(["https://www.youtube.com", iframe.attrs["src"]])
while(1):
try:
html = session.get(next_url, headers=headers)
soup = BeautifulSoup(html.text,"lxml")
# 次に飛ぶurlのデータがある部分をfind_allで探してsplitで整形
for scrp in soup.find_all("script"):
if "window[\"ytInitialData\"]" in scrp.next:
dict_str = scrp.next.split(" = ", 1)[1]
# 辞書形式と認識すると簡単にデータを取得できるが, 末尾に邪魔なのがあるので消しておく(「空白2つ + \n + ;」を消す)
dict_str = dict_str.rstrip(" \n;")
# 辞書形式に変換
dics = json.loads(dict_str)
# "https://www.youtube.com/live_chat_replay?continuation=" + continue_url が次のlive_chat_replayのurl
continue_url = dics["continuationContents"]["liveChatContinuation"]["continuations"][0]["liveChatReplayContinuationData"]["continuation"]
next_url = "https://www.youtube.com/live_chat_replay?continuation=" + continue_url
# dics["continuationContents"]["liveChatContinuation"]["actions"]がコメントデータのリスト。
for samp in dics["continuationContents"]["liveChatContinuation"]["actions"][1:]:
#comment_data.append(str(samp)+"\n")
if 'addChatItemAction' not in samp["replayChatItemAction"]["actions"][0]:
continue
if 'liveChatTextMessageRenderer' not in samp["replayChatItemAction"]["actions"][0]["addChatItemAction"]["item"]:
continue
str1 = str(samp["replayChatItemAction"]["actions"][0]["addChatItemAction"]["item"]["liveChatTextMessageRenderer"]["message"]["runs"])
if 'emoji' in str1:
continue
str1 = str1.replace('[','').replace('{\'text\': \'','').replace('\'}','').replace(', ','').replace(']','')
comment_data.append(str(samp["replayChatItemAction"]["actions"][0]["addChatItemAction"]["item"]["liveChatTextMessageRenderer"]["timestampText"]["simpleText"]))
comment_data.append(","+str1+"\n")
# next_urlが入手できなくなったら終わり
except:
break
# (動画ID).txt にコメントデータを書き込む
url = urlparse(target_url)
query = parse_qs(url.query)
title = query["v"][0] + ".txt"
with open(title, mode='w', encoding="utf-8") as f:
f.writelines(comment_data)
出力されるファイルの内容
ファイル名
(youtubeの動画ID).txt
例 FHR9SwF3ANM.txt
中身
(コメントの時間),(コメントの内容)
例 0:15,おはにゃー
スパチャ、絵文字入りのコメントは、今回自分の目的に必ずしも必要ではなかったので、出力されません。
データ構造が他と違っていて整形がめんどくさかったとは言えない
作成中の試行錯誤
まず、冒頭にリンクした一つ目の記事のコードをそのまま動かしてみたのですが、
テキストファイルには何も出力されませんでした。
pdbモジュールでステップ実行して一行ずつ見てみると、
next_urlに何もURLが入っておらず、エラーを吐きそのまま終了していることがわかりました。
requestsでgetしてきたhtmlのソース内に、live_chat_replayのURLがなかったため、next_urlに何も入らなかったのです。
なぜURLがないのか、正直web系はいままでほぼ触ったことがなかったので、ここでめちゃくちゃ悩みました。
で、いろいろ検索してたら冒頭の3つ目のリンクの記事にたどり着き、無事動かすことができました。
出力するファイルの内容ですが、そのまま吐くとキーとかも出力されて見づらかったので、
時間とコメントのみ吐くようにしました。
スパチャ、メンバー加入、絵文字入りのデータは、やる気があったらそのうち作成したりしなかったりです。
編集歴
evalが危険とのコメントがありましたのでjson.loadsに変更しました。
正直誰が見るねんこの記事と思いながら作成したので、コメントが来てめっちゃうれしかったです。
以上。