実現したいこと
NHKニュースからスクレイピングを行い、タイトル、日時、本文を取得する。
rubyでNHKニュースのスクレイピングを行っています。タイトル、日時、本文の情報を取得するというものです。本文について、途中までは情報を取得できるのですが、途中から末尾に ”.......” という感じで全文を取得できないという問題が起きてしまいます。なにがいけないのでしょうか?
該当のソースコード
require 'nokogiri'
require 'selenium-webdriver'
require 'time'
require 'uri'
class ArticlesController < ApplicationController
def index
@articles = Article.order(created_at: :desc)
end
def create
url = params.dig(:article, :url)
unless url.to_s.include?('nhk') flash[:alert] = "NHKのニュースURLを入力してください。" redirect_to root_path and return end driver = nil begin # --- Selenium Chrome 設定 --- options = Selenium::WebDriver::Chrome::Options.new options.add_argument('--headless=new') options.add_argument('--no-sandbox') options.add_argument('--disable-dev-shm-usage') options.add_argument('--disable-gpu') options.add_argument('--window-size=1920,1080') options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/117.0.0.0 Safari/537.36") options.binary = '/usr/bin/google-chrome' service = Selenium::WebDriver::Service.chrome(path: '/usr/local/bin/chromedriver') driver = Selenium::WebDriver.for(:chrome, options: options, service: service) driver.manage.timeouts.page_load = 40 # --- ページ取得後に「続きを読む」ボタンをクリック --- # --- ページ取得 --- driver.get(url) begin more_button = driver.find_element(xpath: '//button[contains(text(),"続きを読む")]') driver.execute_script("arguments[0].click();", more_button) sleep 1 # 展開待ち rescue Selenium::WebDriver::Error::NoSuchElementError
ボタンがない場合はスルー
end wait = Selenium::WebDriver::Wait.new(timeout: 20) wait.until { driver.find_element(css: 'div.esl7kn2s._1i1d7sh0') } # --- ページを最下部までスクロール(描画完了を促す) --- 100.times do driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") sleep (rand(2.0..10.0)) end # --- 本文取得(Seleniumで描画後のDOMから直接) --- #article_elements = driver.find_elements(css: 'div.esl7kn2s._1i1d7sh0 p._1i1d7sh2') #content = article_elements.map { |el| el.text.strip }.reject(&:empty?).join("\n\n") content = driver.execute_script(<<~JS) const article = document.querySelector('div.esl7kn2s._1i1d7sh0'); if (!article) return ''; const ps = Array.from(article.querySelectorAll('p._1i1d7sh2')); return ps.map(p => p.innerText.trim()).filter(Boolean).join("\\n\\n"); JS # --- 日時取得 --- time_tag_element = driver.find_element(css: 'time[datetime]') rescue nil datetime_str = time_tag_element&.attribute('datetime') published_at = datetime_str ? Time.iso8601(datetime_str).in_time_zone('Asia/Tokyo') : nil # --- タイトル取得(NokogiriでOK) --- doc = Nokogiri::HTML.parse(driver.page_source) title = doc.at_css('h1')&.text&.strip || "タイトル不明" # --- 保存 --- Article.create!( url: url, title: title, published_at: published_at, content: content ) flash[:notice] = "記事を保存しました。" rescue => e flash[:alert] = "スクレイピング中にエラーが発生しました: #{e.message}" puts "[ERROR] #{e.message}" ensure driver&.quit end redirect_to root_path
end
end
あなたの回答
tips
プレビュー