seleniumでgoogleの検索結果を取得してみよう!

railsを覚えるより前に、簡単なphpを覚えた方がいいと思っている昼寝王子です。 今日は、ruby + seleniumでgoogleの検索結果を取得するコードを紹介します。

google検索結果のクローリング

googleの検索結果は、jsなどが動いてhtmlが生成されているので単なるopen-uriなどでは取得が大変難しいです。そこで、使うのがseleniumです。seleniumではブラウザを実際に操作してスクレイピングを行うので、取得ができるのです。 今回はGoogleの検索結果をクローリングして見たいと思います。

早速やってみる

今回は、「伝説の勇者の伝説」というキーワードをGoogle検索し、最初4ページのタイトルを取得するというものを作りたいと思います。

Gemfile

gem 'selenium-webdriver'
gem 'nokogiri'

google-crawler.rb

require 'nokogiri'
require 'selenium-webdriver'

class Crawler
    def get_title_text(driver)
        #Nokogiriを用いてHTMLをパースする
        doc = Nokogiri::HTML.parse(driver.page_source, nil, 'utf-8')
        #ユーザー名を取得
        doc.css('h3.r').each do |h3|
            puts h3.text
        end    
    end

    def main
        ua = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"
        #ブラウザ立ち上げモード
        #caps = Selenium::WebDriver::Remote::Capabilities.chrome('chromeOptions' => {args: ["--user-agent=#{ua}", 'window-size=1280x800']})
        #ヘッドレスモード
        caps = Selenium::WebDriver::Remote::Capabilities.chrome('chromeOptions' => {args: ["--headless","--no-sandbox", "--disable-setuid-sandbox", "--disable-gpu", "--user-agent=#{ua}", 'window-size=1280x800']})
        driver = Selenium::WebDriver.for :chrome, desired_capabilities: caps

        #googleのトップページに移動
        driver.navigate.to "https://www.google.co.jp/"
        #google検索フォームに値を入力
        driver.execute_script("document.getElementById('lst-ib').value = '株式会社ルーター'")
        #検索ボタンをクリック
        driver.execute_script("document.getElementsByName('btnK')[0].click()")

        3.times{|i|
            get_title_text(driver)
            driver.execute_script("document.getElementById('pnnext').click()")
            sleep 2
        }
        get_title_text(driver)
    end
end

Crawler.new.main

bundle installする

$ bundle install --path .bundle

実行結果

クローラーの実行

$ bundle exec ruby google-crawler.rb
伝説の勇者の伝説 - Wikipedia
TVアニメ「伝説の勇者の伝説」公式サイト
伝説の勇者の伝説 | 富士見書房
伝説の勇者の伝説〈1〉昼寝王国の野望 (富士見ファンタジア文庫) | 鏡 貴也 ...
大伝説の勇者の伝説 (16) 昼寝男の結婚 (ファンタジア文庫) | 鏡 貴也 ...
大伝説の勇者の伝説17 団子娘の出す答え (ファンタジア文庫) | 鏡 貴也 ...
Amazon.co.jp: 伝説の勇者の伝説1 昼寝王国の野望 (富士見ファンタジア ...
伝説の勇者の伝説 - アニヲタWiki(仮) - アットウィキ
伝説の勇者の伝説 - アニメ視聴リンク集
・
・
・

上記のように、タイトルが取得できているでしょうか?

解説

簡単な解説をします。

Googleで検索を行う

#googleのトップページに移動
driver.navigate.to "https://www.google.co.jp/"
#google検索フォームに値を入力
driver.execute_script("document.getElementById('lst-ib').value = '株式会社ルーター'")
#検索ボタンをクリック
driver.execute_script("document.getElementsByName('btnK')[0].click()")

ここでは、Googleのトップページに移動&検索を行なっています。 2行目は、seleniumのメソッドを用いてgoogleのトップページに移動してます。 4行目,6行目は、seleniumを通じてJacaScriptを実行しています。 ※JacaScriptの内容がわからない人は、今度書くJavaScriptの記事を読んでください。

HTMLのパースを行う

#Nokogiriを用いてHTMLをパースする
doc = Nokogiri::HTML.parse(driver.page_source, nil, 'utf-8')
#ユーザー名を取得
doc.css('h3.r').each do |h3|
  puts h3.text
end

ここでは、検索後のページ情報をパースして取得しています。 2行目は、HTMLのパースでおなじみのNokogiriを使用しています。今まではここに「open-uri」等で取得したHTMLを渡していたと思いますが、今回はchrome ヘッドレスが開いているページのHTMLを渡したいので、driver.page_sourceメソッドを用いています。 4行目〜6行目は、selenium関係なくNokogiriでHTMLのパースを行なっています。 ※seleniumにも、HTMLから特定の要素の取得ができますが、Nokogiriを使った方が比較的簡単に実装できます。

「次へ」ボタンを押して、次のページを取得する

3.times{|i|
  get_title_text(driver)
  driver.execute_script("document.getElementById('pnnext').click()")
  sleep 2
}
get_title_text(driver)

ここでは、ページングを行なっています。googleのサイトのhtmlコードを見ると、「次へ」というボタンはリンク要素になっています。そのため、これをクリックすることで次のページに移動することができます。 クリックをするにはJavaScriptを用います。

注意点

今回に限らずクローラーは相手のサーバーに対して負荷をかけてしまいます。 Googleの場合は、あまりクローリングしすぎるとブロックされ、しばらく情報が取得できなくなってしまいます。 クローラーを開発する際には、sleepを挟むこと、過度に取得しすぎないことは心に留めておきましょう。