Ruby
Selenium
Capybara
selenium-webdriver

Capybaraで全てのリンク先のページに対して処理する

More than 3 years have passed since last update.

概要

Capybaraで全てのリンク先のページに対して処理をしようとして、ハマったので作りました。
リンク先のページに対して処理する4つのサンプルコードを置いておきます。

実装

全てのaタグに対して処理をします。

処理対象のHTMLサンプル
<a href="./1.html">1</a>
<a href="./2.html">2</a>
<a href="./3.html">3</a>

ページを遷移して処理するタイプ

全てのリンク先へページ遷移して処理します。

画面遷移するタイプ
for i in 0..(all('a').length-1)
  all('a')[i].click
  # 遷移後のページでの処理
  go_back
end

新しいウインドウを開いて処理するタイプ

全てのリンク先を新しいウインドウで開いて処理します。

新しいウインドウを開くタイプ
all('a').each do |link|
  url = link[:href]
  parent_window = current_window
  switch_to_window(open_new_window)
  visit(url)
  # 遷移後のページでの処理
  current_window.close
  switch_to_window(parent_window)
end

リンク先のページでの処理をブロックで渡す関数

全てのリンク先のHTMLを標準出力します。

ecec_all_link
def exec_all_link
  for i in 0..(all('a').length-1)
    all('a')[i].click
    yield
    go_back
  end
end
ecec_all_link { puts title }
#=> Page1 Title
#   Page2 Title
#   Page3 Title

リンク先のページでの処理をブロックで渡して返り値をとる関数

collect_all_link
def collect_all_link
  result = []
  for i in 0..(all('a').length-1)
    all('a')[i].click
    result.push yield
    go_back
  end
  result
end
p collect_all_link { title } #=> ["Page1 Title", "Page2 Title", "Page3 Title"]

失敗例

ハマったパターン1

別のリンクを踏むと戻っても元居たページの情報が取れない

all('a').each do |link|
  link.click
  go_back
end

ハマったパターン2

ページが移動しているのでループ内でも要素が取れない

all('a').each do |link|
  parent_window = current_window
  switch_to_window(open_new_window)
  # この位置でlink[:href]が取得できない
  visit(link[:href])
  current_window.close
  switch_to_window(parent_window)
end

まとめ

Capybaraなどブラウザを使うと、スコープがコード上正しくてもブラウザの挙動に依存するのがわかっていい勉強になりました。
Seleniumを使って動作確認していて、他のパターンは試してないです。
ご指摘などありましたら、よろしくお願いします。

ライセンス

こちらのコードはMITライセンスです。