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 アプリ、無限スクロール、動的フォーム