0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

スクレイピング時のNokogiri/Selenium使い分け基準|AI実務ノート 編集部

0
Last updated at Posted at 2026-01-03

1. 結論(この記事で得られること)

この記事では、Ruby でスクレイピングを実装する際に「Nokogiri と Selenium どちらを選ぶべきか」の判断基準を、実務ベースで解説します。

得られる知識:

  • ✅ 5 秒で判断できる技術選定フローチャート
  • ✅ 各ツールの得意/不得意を踏まえた実装パターン
  • ✅ AI を活用した要素取得の高速化手法
  • ✅ テスト・監視・エラーハンドリングの実務パターン

私自身、3 年前に JavaScript レンダリングのサイトを Nokogiri で無理やり実装して、1 週間無駄にした苦い経験があります。この記事を読めば、そんな無駄な試行錯誤を回避できます。

2. 前提(環境・読者層)

想定読者

  • Ruby でスクレイピングを実装する必要があるエンジニア
  • Nokogiri は触ったことがあるが Selenium は未経験
  • 「とりあえず動く」から「本番で安定稼働する」レベルにしたい
# Gemfile
gem 'nokogiri'
gem 'selenium-webdriver'
gem 'webdrivers' # Chrome driver 自動管理

Ruby 3.0 以上、Chrome 最新版を前提とします。

3. Before:よくあるつまずきポイント

パターン 1:Nokogiri で JavaScript レンダリングサイトを取得

require 'nokogiri'
require 'open-uri'
 
html = URI.open('https://example-spa.com')
doc = Nokogiri::HTML(html)
puts doc.css('.product-list').text
# => "" (空っぽ!)

原因:Nokogiri は HTML パーサーであり、JavaScript を実行しません。SPA や動的ロードされるコンテンツは取得不可。

パターン 2:全部 Selenium にして遅すぎる

require 'selenium-webdriver'
 
driver = Selenium::WebDriver.for :chrome
driver.get('https://static-site.com')
# 5秒待機...
html = driver.page_source
driver.quit

問題:静的サイトなのに毎回ブラウザ起動で 5〜10 秒。100 ページ取得したら 10 分超。

パターン 3:判断基準が曖昧で設計レビューで差し戻し

「とりあえず Selenium で書きました」では、コストとメンテナンス性の観点で NG です。

4. After:基本的な解決パターン

【最重要】使い分けフローチャート

スクレイピング対象のサイトは?
  │
  ├─ 静的 HTML のみ
  │  └→ Nokogiri(高速・軽量)
  │
  ├─ JavaScript でコンテンツ生成
  │  ├─ API が叩ける(Network タブで確認)
  │  │  └→ HTTParty/Faraday で直接 API 取得(最速)
  │  │
  │  └─ API が複雑/認証あり
  │     └→ Selenium(ブラウザ自動化)
  │
  └─ ログイン・CAPTCHA・複雑な操作
     └→ Selenium(人間の操作を再現)

パターン A:Nokogiri の正しい使い方

require 'nokogiri'
require 'open-uri'
 
class StaticScraper
  def initialize(url)
    @url = url
  end
 
  def fetch_titles
    html = URI.open(@url)
    doc = Nokogiri::HTML(html)
 
    doc.css('h2.title').map(&:text).map(&:strip)
  rescue OpenURI::HTTPError => e
    puts "HTTP Error: #{e.message}"
    []
  end
end
 
# 使用例
scraper = StaticScraper.new('https://blog.example.com')
titles = scraper.fetch_titles
puts titles

適用場面:WordPress、静的サイト、サーバーサイドレンダリング

パターン B:Selenium の基本形

require 'selenium-webdriver'
 
class DynamicScraper
  def initialize(url)
    @url = url
    options = Selenium::WebDriver::Chrome::Options.new
    options.add_argument('--headless') # UI なし
    options.add_argument('--disable-gpu')
    @driver = Selenium::WebDriver.for :chrome, options: options
  end
 
  def fetch_dynamic_content
    @driver.get(@url)
 
    # JavaScript 実行完了を待機
    wait = Selenium::WebDriver::Wait.new(timeout: 10)
    wait.until { @driver.find_element(css: '.loaded-content') }
 
    @driver.find_elements(css: '.item').map(&:text)
  ensure
    @driver.quit
  end
end
 
# 使用例
scraper = DynamicScraper.new('https://spa.example.com')
items = scraper.fetch_dynamic_content
puts items

適用場面:React/Vue.js アプリ、無限スクロール、動的フォーム

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?