モーダルを閉じる工作HardwareHub ロゴ画像

工作HardwareHubは、ロボット工作や電子工作に関する情報やモノが行き交うコミュニティサイトです。さらに詳しく

利用規約プライバシーポリシー に同意したうえでログインしてください。

Selenium with Ruby によるWebブラウザの自動操作

モーダルを閉じる

ステッカーを選択してください

お支払い手続きへ
モーダルを閉じる

お支払い内容をご確認ください

購入商品
」ステッカーの表示権
メッセージ
料金
(税込)
決済方法
GooglePayマーク
決済プラットフォーム
確認事項

利用規約をご確認のうえお支払いください

※カード情報はGoogleアカウント内に保存されます。本サイトやStripeには保存されません

※記事の執筆者は購入者のユーザー名を知ることができます

※購入後のキャンセルはできません

作成日作成日
2013/08/02
最終更新最終更新
2018/09/07
記事区分記事区分
一般公開

目次

    Seleniumを使ったブラウザ操作が趣味です。

    人間がブラウザを用いて手作業でできることは、プログラミングによって自動化できます。

    • 業務でのWebシステムの操作
    • 巡回サイトでの定型処理
    • Webアプリケーションの自動テスト
    • etc.

    例えばPerlではWWW::Mechanizeというモジュールを用いて上記のような自動操作が可能です。同様にRubyにもMechanizeというライブラリがあります。

    しかしながら、これらのツールはFirefoxやIEといった各種ブラウザを完全にエミュレートできておらず、例えばJavaScriptが多用されているサイトだと自動化が簡単には達成できなかったりします。そこで、Seleniumという、ブラウザをエミュレートするのではなくブラウザを操作するツールを用いることで作業を自動実行することを試みます。

    Seleniumについて

    Seleniumはブラウザを自動操作するためのプロジェクト群です。簡単な自動化であればSelenium IDEというプロジェクトで開発されているFirefoxのアドオンを使うのがよさそうですが、ここではもっと複雑な自動化にも対応できるSelenium WebDriverの使用方法を紹介します。

    自動化に用いる言語について

    Java, C#, Python, Ruby, Perl, PHPがサポートされていますが、ここではRubyを用いた例を示すことにします。

    公式ドキュメント

    このページで紹介する内容を越えるものは、公式ドキュメントを参照してください。

    インストール (Ruby)

    ターミナルで以下のコマンドを実行します。

    gem install selenium-webdriver
    

    Seleniumを使用するためには、下記二行が必要です。ただし、ruby1.9以降では"require 'rubygems'"は不要です。

    #!/usr/bin/ruby
    require 'rubygems' # not required for ruby 1.9 or if you installed without gem
    require 'selenium-webdriver'
    

    操作するブラウザを指定

    各種ブラウザを操作するためには、それらが事前にインストールされている必要があります。Googleのトップページを表示するだけのサンプルを示します。実行後にブラウザが自動で閉じるかどうかはドライバーに依存します (明示的に閉じるためには、quitメソッドを用います)。サポートされているブラウザのうち、Firefox、Internet Explorer、Google Chromeの使用例を示します。

    Firefox

    Windows、Mac、Linuxで動作が確認されています。

    #!/usr/bin/ruby
    require 'selenium-webdriver'
    
    driver = Selenium::WebDriver.for :firefox
    driver.get "http://google.com"
    

    Internet Explorer

    現在、Internet ExplorerはWindows版しかありませんので、下記サンプルはWindowsでしか動作しません。ブラウザ本体とは別に、IEDriverServerという、SeleniumとブラウザをつなぐソフトをダウンロードしてPATHを通しておく必要があります。2013-8-21(Wed)現在、最新版はGoogle Codeにホスティングされています。こちらからダウンロード可能です。なお、ブラウザ表示倍率の設定を100%以外にしているとエラーが発生することがあります。その場合は100%に設定してからスクリプトを実行してみてください。

    #!/usr/bin/ruby
    require 'selenium-webdriver'
    
    driver = Selenium::WebDriver.for :ie
    driver.get "http://google.com"
    

    Google Chrome

    Linux、Mac、Windowsでの動作が保証されています。GoogleChromeブラウザ本体のインストールとは別に、Chrome Driverという、SeleniumとブラウザをつなぐソフトをダウンロードしてPATHを通しておく必要があります。2015-2-27 現在、最新版はこちらからダウンロード可能です。

    #!/usr/bin/ruby
    require 'selenium-webdriver'
    
    driver = Selenium::WebDriver.for :chrome
    driver.get "http://google.com"
    

    プロキシ設定

    IEとChromeの場合、システムのプロキシ設定を参照するため、そちらを手動で書き換えればよいです。Firefoxに関してはシステムのプロキシ設定を参照せず、独自の設定を持つため、プログラム上での設定が必要になります。

    #!/usr/bin/ruby
    require 'selenium-webdriver'
    
    PROXY = 'proxy.example.com:8080'
    profile = Selenium::WebDriver::Firefox::Profile.new
    profile.proxy = Selenium::WebDriver::Proxy.new(
      :http     => PROXY,
      :ftp      => PROXY,
      :ssl      => PROXY
    )
    
    driver = Selenium::WebDriver.for :firefox, :profile => profile
    driver.get "http://google.com"
    

    http_proxyという環境変数が定義されている場合

    gemなどのプロキシ設定のためにhttp_proxyという環境変数を定義してしまっている場合、その環境変数を削除するかno_proxyという環境変数を別途用意して127.0.0.1を値として代入しておく必要があります。下記のStack Overflowの解決策で記述されているように、ローカルホストで動作しているWebdriverへのアクセスではproxyサーバにアクセスしないようにする必要があるのです。

    Acess denied to /hub/session when launching Firefox webdriver

    The issue was not directly to do with permissions but with an environment
    variable which was not read when we ran as root. We have the http_proxy
    environment variable set with no exclusions for localhost. This meant that
    the Python client was attempting to connect to the WebDriver via the proxy.
    This was not an issue when run as root because http_proxy was not set.
    This issue can be fixed by setting the no_proxy environment variable for localhost.

    Waitをかける

    環境によってはページの読み込みが完了する前に次の処理を開始してしまう場合があります。その場合、セレクターを用いてID指定などで検索しても、JavaScriptで動的に生成される要素などを考慮すると、検索対象が存在しないことになり自動化がうまくいきません。これを回避するために、適宜waitを挟みながら処理を進めるようにプログラミングするとよいです。下記サンプルでは、some-dynamic-elementというIDを持つ要素が (JavaScriptで生成されて) 10秒以内にページ内に出現しない限り例外を投げて、driver.quitで処理を中断するように記述されています。Googleのトップページにはそのような要素はありませんので、10秒後処理が中断されYahooのページは表示されません。

    #!/usr/bin/ruby
    require 'selenium-webdriver'
    
    driver = Selenium::WebDriver.for :firefox
    driver.get "http://google.com"
    
    wait = Selenium::WebDriver::Wait.new(:timeout => 10) # seconds
    begin
      element = wait.until { driver.find_element(:id => "some-dynamic-element") }
    ensure
      driver.quit
    end
    
    # 実行されない
    driver.get "http://www.yahoo.co.jp"
    sleep 10
    

    すべてのfind_element(s) で上記timeout構文が必要となる場合、下記のようにdriverにwaitを設定することで一括して設定できます。

    #!/usr/bin/ruby
    require 'selenium-webdriver'
    
    driver = Selenium::WebDriver.for :firefox
    driver.manage.timeouts.implicit_wait = 10 # seconds
    
    driver.get "http://google.com"
    element = driver.find_element(:id => "some-dynamic-element")
    

    なお、単純なwaitであれば、rubyのsleepメソッドで事足ります。これは目視でページの確認をしながら先に進めたい場合に有効です。

    スクリーンショットを撮影

    ドライバーによってはサポートされていませんが、スクリーンショットを撮影できます。

    #!/usr/bin/ruby
    require 'selenium-webdriver'
    
    driver = Selenium::WebDriver.for :firefox
    driver.get "http://google.com"
    driver.save_screenshot "/tmp/google.png"
    

    ページ情報 (URL、タイトル、HTML) を取得

    #!/usr/bin/ruby
    require 'selenium-webdriver'
    
    driver = Selenium::WebDriver.for :firefox
    driver.get "http://www.example.com/"
    
    p driver.current_url
    p driver.title
    p driver.page_source
    

    要素セレクタ

    セレクタメソッドは二種類あります。

    • find_element: 該当要素がなければ例外を投げます
    • find_elements: 結果を配列で返します。該当要素がなければ空の配列を返します

    上記セレクタメソッドに与える式としては、XPathやjQueryでもお馴染のCSSセレクタ等があります。

    サンプルコード:

    #!/usr/bin/ruby
    require 'selenium-webdriver'
    
    driver = Selenium::WebDriver.for :firefox
    driver.get "http://www.example.com/"
    
    # 一般のセレクタ
    elements = driver.find_elements(:id => "myid") # ID <div id="myid"></div>
    elements = driver.find_elements(:class_name => "myclass") # クラス <div class="myclass"></div>
    elements = driver.find_elements(:tag_name => "div") # タグの種類 <div class="myclass1"></div>, <div class="myclass2"></div>,...
    elements = driver.find_elements(:name => "myname") # 名前 <div name="myname"></div>
    elements = driver.find_elements(:xpath => "address") # XPath
    elements = driver.find_elements(:css => "ul#smaple-id li") # CSSセレクタ
    
    # <a>タグに特化したセレクタ
    elements = driver.find_elements(:link_text => "click") # <a href="">click</a>
    elements = driver.find_elements(:partial_link_text => "click") # <a href="">click here</a>
    
    # メソッドチェーン
    elements = driver.find_element(:tag_name => "body").find_elements(:xpath => 'div/p/a')
    
    # イテレート
    elements.each do |element|
      puts element.text.encode('UTF-8')
    end
    

    CSSセレクタおよびXPathの簡単な設定 (Firefox)

    複雑なサイトの自動化を試みる場合、CSSセレクタおよびXPathの設定が困難です。Firefoxのアドオンを利用することで設定の手間が削減できます。

    • Firebug: 要素インスペクタで選択した後、右クリックでCSSセレクタまたはXPathを取得可能
    • Firefinder for Firebug: CSSセレクタまたはXPathで実際に要素を選択できるかテスト可能

    要素情報を出力

    # 指定した要素内のテキストを取得 (jQueryと似ている)
    p element.text
    p element.attribute("id")
    

    リンクを押す

    element.click
    

    戻る/進む

    driver.navigate.back
    driver.navigate.forward
    

    フォームへの情報入力およびサブミット

    # フォームの内容をクリア
    element.clear
    
    # inputまたはtextarea要素への値の代入
    element.send_keys("my name");
    
    # ラジオボタン
    elements[3].click
    
    # ドロップダウンリスト
    select = driver.find_element(:tag_name => "select")
    all_options = select.find_elements(:tag_name => "option")
    all_options.each do |option|
      option.click if (true) # 何かしらの条件を指定
    end
    
    # ドロップダウンリストの別の記述方法
    select = Selenium::WebDriver::Support::Select.new(driver.find_element(:tag_name => "select"))
    select.select_by(:index, 0) # 0,1,2,...
    # select.select_by(:text,  "mytext") # 表示されるテキストによる選択
    # select.select_by(:value, "myvalue") # valueによる選択
    
    # サブミット (elementが所属するformのサブミットが行われる)
    element.submit
    

    ウィンドウを複数開く

    driver = Selenium::WebDriver.for :firefox
    driver.get "http://www.example.com/"
    
    driver2 = Selenium::WebDriver.for :firefox
    driver2.get "http://www.example.com/"
    

    ポップアップボックスを処理する

    JavaScriptのalert(), confirm(), prompt()関数によって、ポップアップボックスが表示されるページがあります。Seleniumでそれらを制御するためには、まず

    alert = driver.switch_to.alert
    

    によって制御対象をアクティブなポップアップボックスに移します。そして、下記4つのメソッドによって制御ができます。ポップアップボックスが消えた後は自動的に制御はもとのブラウザに戻ります。

    • alert.text によってボックス内のテキストを取得 (alert,confirm,prompt)
    • alert.accept によって「はい」「OK」ボタンをクリック (alert,confirm,prompt)
    • alert.dismiss によって「いいえ」「キャンセル」ボタンをクリック (confirm,prompt限定)
    • alert.send_keys "some text input" によって入力ボックスへの値の入力 (prompt限定)

    なお、これらのメソッドでは基本認証あるいはベーシック認証と呼ばれるものへの入力はできませんのでご注意ください。

    ダウンロードファイルを確認なしで自動的に保存する (Firefox)

    CSVやzipファイルをダウンロードする場合、既定では「アプリケーションで開くかダウンロードして保存するか」を確認するポップアップボックスが表示されます。このポップアップボックスを表示されてしまうと以降の自動化ができないため、Firefoxのプロフィール (URLバーにabout:configと入力して確認および変更ができる、Firefoxの挙動の設定群) を設定して指定のディレクトリに確認なしで保存するようにします。

    profile = Selenium::WebDriver::Firefox::Profile.new
    
    # ファイルをダウンロードする既定のフォルダ
    # - 0: デスクトップ
    # - 1: システム既定のダウンロードフォルダ
    # - 2: ユーザ定義フォルダ (browser.download.dir で指定)
    profile['browser.download.folderList'] = 2
    
    # ダウンロード先を指定 (バックスラッシュが二つ必要。環境によっては1つだけでいいかも)
    profile['browser.download.dir'] = 'C:\Users\YourName\Desktop'
    
    # ファイルをポップアップボックスなしで自動的に保存 (CSVファイルの例)
    profile['browser.download.useDownloadDir'] = true
    profile['browser.helperApps.neverAsk.saveToDisk'] = "text/plain,
      application/vnd.ms-excel,text/csv,text/comma-separated-values,application/octet-stream"
    
    # ドライバーを生成
    driver = Selenium::WebDriver.for :firefox, :profile => profile
    

    ドラッグ・アンド・ドロップ

    element = driver.find_element(:name => 'source')
    target = driver.find_element(:name => 'target')
    
    driver.action.drag_and_drop(element, target).perform
    
    Likeボタン(off)0
    詳細設定を開く/閉じる
    アカウント プロフィール画像

    Seleniumを使ったブラウザ操作が趣味です。

    記事の執筆者にステッカーを贈る

    有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。

    >>さらに詳しくステッカーを贈る
    ステッカーを贈る コンセプト画像

    Feedbacks

    Feedbacks コンセプト画像

      ログインするとコメントを投稿できます。

      ログインする

      関連記事

      • レイアウトおよび部分テンプレートに関するまとめ (Rails4)
        レイアウトおよび部分テンプレートはどちらもテンプレート (*.html.erb) に共通の要素をまとめておき、任意のテンプレートから利用できるようにしておくための仕組みです。フッターやヘッダーといった大枠はレイアウト、小さなパーツは部分テンプレートというイメージで使い分けましょう。 レイアウトの使用方法 クラス毎に指定する方法と、アクション毎に指定する方法があります。 app/views/layo...
        taro三世taro三世9/21/2016に更新
        いいねアイコン画像0
      • Ruby コードスニペット (正規表現)
        sample.rb str = "001: This is a string." var1,var2 = 2,3 # 'EOS'とすると#{}による変数展開がなされない (%03dは展開される) doc = (<<"EOS" % var1) # 括弧は省略可。要は<<"EOS"の次の行からEOSまで。(参: <<-"EOS"とすると前に空白...
        だいふくうさぎだいふくうさぎ4/13/2018に更新
        いいねアイコン画像0
      • OAuthを用いずにTwitterに自動投稿する (回数制限あり, Selenium with Ruby)
        Seleniumを用いて、OAuthを用いずにTwitterに自動投稿するRubyスクリプトを記述してみます。連続で複数回実行すると、ボット判定としてキャプチャ認証が発生します。その認証までは通過できませんので悪しからず。また、Twitterの仕様変更次第ではDOMの構造が変化するため、下記サンプルは機能しなくなる恐れが有ります。 twitter_post.rb #!/usr/bin/ruby r...
      • Ruby における日本語のエンコーディング
        日本語を含めて多言語対応する際には、Asciiコード以外の文字コードセットが必要になります。日本語が主となる場合、よく使われる文字セットにはUnicode, Shift_JIS, EUC-JPがあります。このうち Unicode だけは特殊であり、世界中のあらゆる文字を収録しようとしていることから 1 文字を表現するために必要なバイト数が大きくなってしまっています。そのため Unicode のうち...
        だいふくうさぎだいふくうさぎ3/21/2017に更新
        いいねアイコン画像0
      • Rails3ビューテンプレートの基本的な使用方法 (Ruby)
        Railsでは、ERB (eRuby (テキストファイルにRubyスクリプトを埋込む書式の仕様) をRubyで実装したもの) を用いてHTML内にRubyスクリプトを埋込むことができます。 <% %> で囲むと出力されません (if-elseなど制御構文を記述します) <%= %> で囲むとエスケープ出力されます <%== %> で囲むとエスケープされずに...