こんにちは、Webサービスを作るとなったら、真っ先にphpを使っているイタヤです。 今回は、この間記述した「chromeヘッドレスの環境構築」の続きです。前回はテキストを1つとって終了でしたが、今回は少し発展させて、クローリングするところまで説明したいと思います。

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

今回は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
株式会社ルーター – データクローリング・スクレイピングによるビッグデータ収集
株式会社ルーターの会社情報 - Wantedly
株式会社ルーターのメンバー - Wantedly
株式会社ルーターのアルバイト・バイト求人情報 | 仕事探しは【マッハバイト】
株式会社ルーター(代表:前田 芳紀)の会社概要 | Find Job!
株式会社ルーターの求人・転職情報 | Find Job!
株式会社ルーター 【業務未経験者歓迎】サーバーサイトの開発エンジニア ...
携帯端末などのアフターサービス業務のコンサルタント 株式会社ルーター
株式会社ルーターの求人 | Indeed (インディード)
株式会社ルーター(84241)の転職・求人情報|【エンジャパン】のエン転職
株式会社ルーター - ホーム | Facebook
株式会社ルーターのアルバイト・バイト求人情報|【タウンワーク】でバイトや ...
株式会社ルーター(84241)の転職・求人情報一覧|エン転職
株式会社ルーター アルバイトの求人 - 東京都 新宿区 東新宿駅 | Indeed ...
・
・
・

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

解説

前回は、しなかったのでソースコードの解説をしようと思います。

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を挟むこと、過度に取得しすぎないことは心に留めておきましょう。

まとめ

今回は、seleniumを用いてスクレイピングをする手法についてまとめました。 僕自身JavaScriptが好きであるというもあり、「リンクのクリック」「検索フォームに値を入れる」などの動作をJavaScriptで実装しましたが、selenium自身にも値を入れたり、クリックしたりするメソッドがあるので、そちらを使うのも良いでしょう。 ただ、JavaScriptは知っていて損のない言語なので、この機会にぜひ覚えて見てはどうでしょうか??