ヤフーニュース記事の大量のコメントを自動取得する方法 pythonスクリプト, selenium, chromedriver, ChatGPT

ヤフーニュース記事で国民の関心が高いものに関しては数千件、場合によっては数万件ものコメントが付きます。いちいち全部読むのはもはや無理で、要約するとか、分析して傾向ごとに分けるとか何らかの機械学習的な処理の助けを借りない限りどうしようもないでしょう。

仮に、本を読むようなつもりでコメントを全部読みたいと思っても、10件ずつブラウザをクリックしながら2000ページ(2万コメントの場合)もクリックし続けるのは誰もやりたくないことです。一つの文書に落とし込めれば、まだ全部読むというオプションにも現実味があります。

そんなときに、とりあえずヤフーコメント全てを文書データとしてダウンロードして保存する必要があります。ネットにそのような処理をするスクリプトがいくつか公開されていましたが、自分が試したかぎりなにも修正せずに動作するものはありませんでした。

そこで、修正するだけのプログラミング能力もないためChatGPTに自分のやりたいことを伝えて、スクリプトをゼロから書いてもらいました。一度で欲しいものが得られたわけではなく、エラーが出たりうまくデータが取得できなかったりで10回くらいのやり取りの末にようやく正常に動作する完成版ができたようなので、ここにシェアします。

 

ウェブブラウザはグーグルChromeを使います。Seleniumというライブラリーで自動的にウェブブラウザを開くので、Seleniumのインストールを予めしておく必要があります。またChromeのドライバー(chromedriver)を正しいパスに置いておく必要があります。

  1. chromedriverのダウンロードサイト https://googlechromelabs.github.io/chrome-for-testing/

コメントはエクセルファイルに保存されます(ダウンロードフォルダ内)。1行につき1つのコメントです。

ちなみに自分の場合は、ウインドウズ11でAnaconda3、jupyter notebookという環境です。環境に依存するようなことは何もないはずなので、多分ウインドウズであろうが何であろうが、Selenium, Chromedriverが使える条件であれば、動くと思います。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
import time
import pandas as pd

# 使い方:
# 下のbase_urlとmax_pageの値は、自分で決めて入れてください。
# base_url ヤフーニュース記事の「コメント」を表示し、「新着順」を選んだときのurl
base_url = "https://news.yahoo.co.jp/articles/0149d024655889eadd8f3fb4a8fcfd1838451a89/comments?order=newer"
# max_pages コメントはページ当たり10件なので、総コメント数÷10を切り上げた数字もしくはもっと大き目な数字でもよい
max_pages = 100  # コメントの最大ページ数

def scroll_page(driver):
    """
    ページをスクロールしてコメントをすべて表示する。
    """
    last_height = driver.execute_script("return document.body.scrollHeight")
    while True:
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
        time.sleep(2)  # 動的ロードの待機
        new_height = driver.execute_script("return document.body.scrollHeight")
        if new_height == last_height:
            break
        last_height = new_height


def get_comments_from_page(driver, page):
    """
    現在のページからすべてのコメントを取得。
    """
    comments = []
    try:
        print(f"Processing page {page}...")
        scroll_page(driver)  # ページ全体をスクロール

        # 全てのコメント要素を取得(異なる構造に対応)
        comment_elements = driver.find_elements(By.XPATH, "//p[contains(@class, 'sc-z8tf0-11') or contains(@class, 'sc-169yn8p-10')]")
        print(f"Found {len(comment_elements)} comments on page {page}.")

        for index, element in enumerate(comment_elements):
            try:
                # 「もっと見る」がある場合はクリック
                more_button = element.find_element(By.CLASS_NAME, "sc-1nejiws-0")
                driver.execute_script("arguments[0].click();", more_button)
                time.sleep(1)
            except:
                pass  # 「もっと見る」がない場合はスキップ
            
            # コメント全体を取得
            comments.append(element.text.strip())
            print(f"Comment {index + 1}: {element.text.strip()[:30]}...")  # ログに表示
    except Exception as e:
        print(f"Error processing page {page}: {e}")
    return comments


def scrape_comments(base_url, max_pages):
    """
    全ページからコメントをスクレイピングする。
    """
    driver = webdriver.Chrome()  # ChromeDriverを使用
    driver.get(base_url)
    all_comments = []

    for page in range(1, max_pages + 1):
        print(f"Scraping page {page}...")
        if page > 1:  # 2ページ目以降
            next_page_url = f"{base_url}&page={page}"
            driver.get(next_page_url)
            time.sleep(3)  # ページロード待機

        # コメントを取得
        comments = get_comments_from_page(driver, page)
        if not comments:  # コメントがない場合終了
            print("No more comments found. Exiting loop.")
            break
        all_comments.extend(comments)  # 各ページのコメントをリストに追加
    
    driver.quit()
    return all_comments

# スクレイピング実行
comments = scrape_comments(base_url, max_pages)

# コメントをExcelに保存
if comments:
    # 別名で保存してファイル競合を防ぐ
    output_file = f"yahoo_news_comments_{int(time.time())}.xlsx"
    df = pd.DataFrame(comments, columns=['Comment'])  # 全コメントをDataFrame化
    df.to_excel(output_file, index=False)
    print(f"Comments saved to {output_file}")
else:
    print("No comments found or failed to scrape.")

正常に動作することを確認しましたが、もしもっと自分が使いやすいように細かく調整したければ、上のスクリプトをChatGPTに投げて、カスタマイズすれば、プログラミング能力は全く不要でやりたいことができると思います。

プログラミング能力がほぼゼロの自分でもChatGPTがあればやりたいことが実現できてしまうというのが驚きです。