かしいさんのはじめて個人開発

お笑いライブ検索サイト「ワラリー!」を運営しているフリーのWEBエンジニアです。超ド初心者がつまづきがちな、個人開発にまつわるあれこれを書いていきます。

【Ruby】Seleniumでスクレイピング: あるあるエラー5選

f:id:bitokosubcul:20190515051101p:plain
Webスクレイピングに役立つツール「Selenium」を使うときにおこりがちなエラー5選をまとめました。

はじめに

Seleniumは複雑な操作をするWebスクレイピングするときに役立つgemです。

RubyでWebスクレイピングするときに使えるgem

  • Nokogiri (基本)
  • Mechanize (かんたん)
  • Selenium (ブラウザ操作でいろいろできる)

NokogiriやMechanizeでは、HTMLタグやCSSを指定してページの内容を取得します。
Seleniumではプログラムでブラウザを開いて擬似的に操作できるので、複雑な処理ができます。

  • ログインが必要な場合
  • JavaScriptでページを描画している場合
  • データを入力したい場合

など、HTMLタグやCSSセレクタだけでは必要な情報を取得できないときに使用すると便利です。

Seleniumの使い方

Seleniumの使い方はいろんな方がまとめてくれているのでそちらを見てください。

qiita.com

morizyun.github.io

# Selenium使用に必要なツールをインストール
require 'selenium-webdriver'

# Seleniumを起動
driver = Selenium::WebDriver.for :chrome

Seleniumを使うときのあるあるエラー5選

1. ブラウザとSeleniumを動かすツールのバージョンが違う

Selenium::WebDriver::Error::SessionNotCreatedError (session not created: This version of ChromeDriver only supports Chrome version 75)

Seleniumではブラウザの種類を指定してプログラムでマウスを動かします。

# seleniumの起動
driver = Selenium::WebDriver.for :chrome

Chromeを使いたい場合はChromeと同じバージョンのChromedriverをインストール。
FirefoxやChromeなど、使用したいブラウザを開発環境にインストールしておく必要があります。

Google Chromeのバージョン確認方法
Google Chromeの設定>ヘルプ>Google Chromeについてから、バージョンを確認
f:id:bitokosubcul:20190515051326p:plain

Chromedriverのインストール方法
qiita.com

Herokuにデプロイして使う場合は、Heroku上にもGoogle ChromeとChromedriverのインストールが必要です。 また、Chromeをheadlessで動かすためのオプションを追加する必要があります。
ikapblg.blog.fc2.com

katsulog.tech

qiita.com

2. Webページを開けなかった

Selenium::WebDriver::Error::InvalidArgumentError (invalid argument: 'url' must be a string)

ダメな例:変数で渡す

# URLを開く
@url = 'https://www...'
driver.get(@url)
driver.get("#{@url)")

()の中がrubyの変数だとダメなのか? 文字列にしろと怒られました。

OKな例:文字列をそのまま書く

# URLを開く
driver.get('https://www...')

3. ページ内の要素をうまく取得できなかった

Selenium::WebDriver::Error::NoSuchElementError: no such element: Unable to locate element: {"method":"id","selector":"#entryBtn"}

HTML/CSSに対応する要素がないときに起こるエラー。
クラス名などをちゃんと指定できてるかチェック。

nokogiriの場合:CSSセレクタで要素を指定

CSSセレクタで取得したい要素を指定します。

# nokogiri使用に必要なツールをインストール
require 'nokogiri'
require 'open-uri'

# Nokogiriを使用してページの要素を取得
html = Nokogiri::HTML(open('https://www.google.co.jp/'))
logo = html.css('#hplogo')

seleniumの場合:要素の種類+要素名(HTMLタグ、CSSのクラス名など)で要素を指定

要素の種類+要素名で取得したい要素を指定します。

# selenium使用に必要なツールをインストール
require 'selenium-webdriver'

# Seleniumを起動してページの要素を取得
driver = Selenium::WebDriver.for :chrome
driver.find_element(:id, 'hplogo') 

seleniumだと「#」がいらない。

4. ページ上にないSelenium要素に対して操作をしている

Selenium::WebDriver::Error::StaleElementReferenceError (stale element reference: element is not attached to the page document)

ブラウザバックして、前のページにあった要素に対して操作しようとしたときに起きたエラー。

ダメな例:ループの2回目以降で変数が空になってしまっている

# selenium使用に必要なツールをインストール
require 'selenium-webdriver'

# Seleniumを起動
driver = Selenium::WebDriver.for :chrome

# イベント一覧ページからイベント詳細ページのURLを取得する
events = driver.find_elements(:class, 'eventItem')

# イベント詳細ページへ移動する
for i in 0..events.size()-1
  # イベント詳細ページへのボタンをクリック
  events.find_element(:class, 'entryBtn').click()
 # →2回目以降のループ処理でエラーになる

  # 前のページに戻る
 driver.navigate.back
end

OKな例:ループ処理の中で要素を取得し直す

# selenium使用に必要なツールをインストール
require 'selenium-webdriver'

# Seleniumを起動
driver = Selenium::WebDriver.for :chrome

# イベント一覧ページからイベント詳細ページのURLを取得する
events = driver.find_elements(:class, 'eventItem')

# イベント詳細ページへ移動する
for i in 0..events.size()-1
  # 2回目以降のループ処理の際にドライバがなくなってるので、再度ドライバ指定
  events_in_loop = driver.find_elements(:class, 'prfItem')

  # イベント詳細ページへのボタンをクリック
  events_in_loop[i].find_element(:class, 'entryBtn').click()

  # 前のページに戻る
 driver.navigate.back
end

ループしているとドライバが有効でなくなってしまうので、ループ内でもう一度ドライバを取得し直す必要がある。

参考

stackoverflow.com

5. Rubyのコマンドが入力できなくなる

「終わった〜」という感じの環境構築系エラーです。

 `require': incompatible library version - /Users/cathy/Desktop/work/vagrant/Test/vendor/bundle/ruby/2.5.0/gems/pg-0.19.0/lib/pg_ext.bundle (LoadError)

gemをアンインストールしたりしてたら別のエラーが出て抜け出せなくなりました…

/Users/cathy/.rbenv/versions/2.5.1/lib/ruby/site_ruby/2.5.0/rubygems/core_ext/kernel_require.rb:54:in `require': cannot load such file -- rubygems/core_ext/kernel_warn (LoadError)

Seleniumのgemがなくなってしまったのにrequire 'selenium-driver'の記述があることが原因らしい?

teratail.com

いろいろやっても解決しないので、結局Rubyのバージョンをあげたらなんとか動くようになりました。

qiita.com