雑記帳(@watagasi_)

PythonでYouTube Liveのアーカイブからチャット(コメント)を取得する(改訂版)

※この記事の内容はかなり古くなっており、2020年11月頃のYouTube Liveのチャットの仕様が変わって今(2021/12/19現在)はpytchatというライブラリを使うのが良いと思われます。
github.com


watagassy.hatenablog.com

前回このような記事を書きまして、seleniumを用いたスクレイピングを行うといった形でプログラムを記載していましたが、selenium使わなくて良いんじゃね?ということが判明したので、こちらに改訂版のコードを書いておきます。

この変更に伴い、前回のプログラムの問題点であった「めちゃくちゃ遅い」という部分が解消されています。



from bs4 import BeautifulSoup
import json
import requests

target_url = youtube_url
dict_str = ""
next_url = ""
comment_data = []
session = requests.Session()
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を入手
html = requests.get(target_url)
soup = BeautifulSoup(html.text, "html.parser")

for iframe in soup.find_all("iframe"):
    if("live_chat_replay" in iframe["src"]):
        next_url= iframe["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.text:
                dict_str = scrp.text.split(" = ")[1]

        # javascript表記なので更に整形. falseとtrueの表記を直す
        dict_str = dict_str.replace("false","False")
        dict_str = dict_str.replace("true","True")

        # 辞書形式と認識すると簡単にデータを取得できるが, 末尾に邪魔なのがあるので消しておく(「空白2つ + \n + ;」を消す)
        dict_str = dict_str.rstrip("  \n;")
        # 辞書形式に変換
        dics = eval(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"]がコメントデータのリスト。先頭はノイズデータなので[1:]で保存
        for samp in dics["continuationContents"]["liveChatContinuation"]["actions"][1:]:
            comment_data.append(str(samp)+"\n")

    # next_urlが入手できなくなったら終わり
    except:
        break

# comment_data.txt にコメントデータを書き込む
with open("comment_data.txt", mode='w', encoding="utf-8") as f:
    f.writelines(comment_data)

基本的な構造はほぼ変わっていませんが、htmlの取得をdriver.get(next_url)からsession.get(next_url, headers=headers)に変更しています。




いろいろ試している間に、スーパーチャットなどが導入されている場合はコメントデータの構造が違うことなどが判明したので、それらに対応した追記もこちらでしていこうと思います。