Mechanizeでページ遷移しながらスクレイピング

ちょっとダルいポイントが有ったのでメモ程度に。
スクレイピング対象サイトとスクレイピングの流れは

  • ページャで何ページか一覧ページがある
  • 一覧ページのタイトルをクリックすると詳細ページが見れる
  • 詳細ページの一部を使用
  • また他のタイトルをクリックしていく
  • CSVで出力(別にいらないけどメモ代わりに。。)

みたいな感じです。mechanizeだけでやります。

require 'mechanize'
require 'csv'

class ScrapingPages

  def initialize
    @agent = Mechanize.new
    @data = []
  end

  def retrieve
    # 1ページ目から10ページ目までスクレイピングする
    (1..10).each do |i|
      page = @agent.get(url(i)
      each_section(page) do |section|
        title = section.css('h2.title > a').first.text
        detail = @page.links_with(text: title).first.click
        @data << {
          title: title,
          detail: detail.links.first.text
        }
      end
    end
  end

  def each_section(page)
    page.search('.articleBox').each do |section|
      yield section
    end
  end

  def url(current_page)
    "https://hogehoge.com/#{current_page}"
  end

  def make_file_as_csv
    CSV.open("./csv/scraping-#{Time.now.to_i}.csv", "wb", encoding: 'Shift_JIS') do |csv|
      csv << %w(title detail)
      @data.each do |record|
        csv << [record[:title], record[:detail]]
      end
    end
  end
end

scraping_pages = ScrapingPages.new
scraping_pages.retrieve
scraping_pages.make_file_as_csv

コードは実際のものとちょこちょこ変更箇所あるので流しでいいのですが、ポイントはclickのところ。
mechanizeは中でnokogiriを使っているようで、
上記の@agent, pageとかはmechanizeクラスが 親のオブジェクトなのですが、
.cssとか使うと返ってくるオブジェクトがnokogiriクラスのインスタンスオブジェクトが返ってきます。

で、clickメソッドはmechanizeクラスに対してしか使えないので、微妙に工夫が必要。

title = section.css('h2.title > a').first.text
detail = @page.links_with(text: title).first.click

# .css('h2.title > a').first.clickとかすると、
# nokogiriがclickメソッド持ってないのでエラーになる。

ここです。title変数で一旦クリック個所のテキストを格納しておいて、
mechanizeクラス継承の@pageに対してリンクを辿って
テキストを指定してクリックする、と。

csvはよく忘れるのでメモ程度に載せただけです。

もっと良いやり方あるかもだけど。