【Python】YouTubeのコメント情報をテキストファイルに書き出す

PG,Python

処理概要

処理内容

  1. 対象のURLを開く
  2. 可能な限りページをスクロールする
  3. コメント情報を取得する
  4. Good評価が1つ以上あればコメントを取得する
  5. 取得したGood数とコメントをテキストファイルに出力する

入力ファイル

  • ファイル名:url_list.txt
  • 実行ディレクトリに配置する

出力ファイル

  • ファイル名:ページタイトル.txt
  • 実行ディレクトリに出力される

注意

  • バックグラウンドで実行しているが音声が流れる

無限スクロールの対応

  • ページスクロールの実行前後でコメントエリアの情報の変化を比較する。
  • ここでは座標情報の変化を比較し、実行前後で差があればスクロールする余地があり、差がなければスクロールしきったと判断する。
  • 比較処理はスクロール後なので、正確には「余地があった」「スクロールしきっていた」ことになる。

これ以外にもページの情報量全体を比較する手段があるが、処理が重くなる場合があるのでなるべく変化のある部分だけに限定したほうが良い。

ページスクロールの処理概要

  1. スクロール前のコメントエリアのサイズを取得
  2. ページのスクロールを実行
  3. スクロール後のコメントエリアのサイズを取得
  4. スクロール前後のサイズを比較
  5. 4.で違いがなくなるまで繰り返し

入力ファイル

対象URLのサンプル

https://www.youtube.com/watch?v=qbEx4fK6TKE
https://www.youtube.com/watch?v=SO51jyCs3PA

コード

# ----------------------------------------
# モジュールのインポート
# ----------------------------------------
import os
import time
import tkinter.messagebox

import chromedriver_binary
from selenium import webdriver
from selenium.webdriver.chrome import service as fs
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from webdriver_manager.chrome import ChromeDriverManager

# メッセージボックス用の設定
root = tkinter.Tk()
root.withdraw()

# ----------------------------------------
# 入力ファイルの読み込み
# ----------------------------------------
input_file = r'url_list.txt'
url_list = []
if os.path.exists(input_file):
    with open(input_file, mode='r', encoding='utf-8') as f:
        for i in f:
            url_list.append(i)

    input_row = len(url_list)
    print(f'処理対象件数: {input_row}')

    if input_row < 1:
        tkinter.messagebox.showwarning('件数チェックエラー', '処理対象データがないため処理を終了します。')
        exit()

else:
    tkinter.messagebox.showerror('ファイルチェックエラー', f'『{input_file}』が存在しないため処理を終了します。')
    exit()

# ----------------------------------------
# ChromeDriverの設定
# ----------------------------------------
# ChromeDriverの最適化
CHROMEDRIVER = ChromeDriverManager().install()

# オプションの設定
chrome_service = fs.Service(executable_path=CHROMEDRIVER)
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
chrome_options.add_experimental_option('excludeSwitches', ['enable-automation', 'enable-logging'])

# ----------------------------------------
# 処理開始
# ----------------------------------------
print('>処理開始')
driver = webdriver.Chrome(service=chrome_service, options=chrome_options)
driver.maximize_window()
driver.implicitly_wait(5)

# リスト中のURLを繰り返す
for url in url_list:
    driver.get(url)
    content = driver.find_element(By.TAG_NAME, 'body')

    # タイトルが取得できなかったらYouTubeページではないと判断
    try:
        title = driver.find_element(By.XPATH, '//*[@id="title"]/h1/yt-formatted-string').text
        print(f'>>ページタイトル:{title}')

        # 事前にページをスクロールしきっておく
        com_area = driver.find_element(By.ID, 'contents')
        before_scroll = com_area.location
        while True:
            print('>>ページスクロール中…')
            content.send_keys(Keys.END)
            time.sleep(3)
            after_scroll = com_area.location
            if before_scroll != after_scroll:
                before_scroll = after_scroll
            else:
                print('<<ページスクロール終了')
                break

        # Good評価のついているコメントを取得して出力する
        print('>>>書込処理開始')
        with open(f'{title}.txt', 'w', encoding='utf8') as f:
            i = 1
            while i > 0:
                try:
                    good_xpath = f'/html/body/ytd-app/div[1]/ytd-page-manager/ytd-watch-flexy/div[5]/div[1]/div/div[2]/ytd-comments/ytd-item-section-renderer/div[3]/ytd-comment-thread-renderer[{i}]/ytd-comment-renderer/div[3]/div[2]/ytd-comment-action-buttons-renderer/div[1]/span[2]'
                    good = driver.find_element(By.XPATH, good_xpath)

                    # Goodが1つ以上あったらその数とコメントを書き込む
                    if good.text != '':
                        com_xpath = f'/html/body/ytd-app/div[1]/ytd-page-manager/ytd-watch-flexy/div[5]/div[1]/div/div[2]/ytd-comments/ytd-item-section-renderer/div[3]/ytd-comment-thread-renderer[{i}]/ytd-comment-renderer/div[3]/div[2]/div[2]/ytd-expander/div/yt-formatted-string'
                        com = driver.find_element(By.XPATH, com_xpath)
                        com_text = com.text.replace('\n', '')
                        f.write(f'【{good.text}】\t')
                        f.write(f'{com_text}\n')

                    i += 1
                except:
                    i = 0
        print('<<<書込処理終了')

    except:
        print('適切なURLではありません')
        pass

    time.sleep(3)

# ----------------------------------------
# 処理終了
# ----------------------------------------
print('<処理終了')
tkinter.messagebox.showinfo('処理終了', '処理が終了しました')
driver.quit()

PG,Python

Posted by junichi