スリ飯屋Malankaのフリーエンジニアな日々

IT実務未経験から約1年、東京でフリーランスのRuby on Railsエンジニアに転職。約2年半、大阪中崎町でスリランカカレーの間借りしてました。フリーランスエンジニアになるためのノウハウ、スリランカの事を発信していきます。

【Ruby Selenium】wait.untilブロックでTimeoutしたら外側にraiseされる

【Selenium】wait.untilブロックでTimeoutしたら、waitの外側にraiseされる

こんにちは、mahです。

このブログでは、僕がIT未経験から約1年でフリーランスエンジニアになるまでの過程、ノウハウなどを書いていきます。


今回は、

  • Seleniumの、wait.untilブロックでTimeoutしたら、waitの外側にraiseされる

についてです。


Seleniumリファレンス


Seleniumクイックリファレンス


概要


Seleniumは、

find_element(s) というメソッドで要素を検索し、

要素が見つからなければエラーが発生します。


Seleniumのブラウザ処理は高速なので、

ページ上に要素が現れていない状態でも、

次々にクリックやページ遷移をしていきます。


ただそれだとエラーになるので、

  • 「特定の要素がページに表示されるまで、一定時間待機する」

という処理を加えて、

エラーを防止するのが定石です。


その待機時間を過ぎた場合は、

Selenium::WebDriver::Error::TimeoutError

が発生します。


このタイムアウトエラーの例外処理でハマりました。


コードで説明します。

ダメだったコードの例


def sample
  driver = Selenium::WebDriver.for :chrome

  # タイムアウトまでの時間
  wait = Selenium::WebDriver::Wait.new(timeout: 60)

  wait.until do
    driver.find_element(:id, 'search-result')&.displayed?
  rescue Selenium::WebDriver::Error::TimeoutError => e
    raise Selenium::WebDriver::Error::NoSuchElementError
  rescue Selenium::WebDriver::Error::NoSuchElementError => e
    Rails.logger.error <<~EOS
      エラー
      #{e}
    EOS
    nil
  end
end


上記のコード、wait.untilブロックの中の

driver.find_element(:id, 'search-result')&.displayed?

で、find_elementで要素が見つからなかった場合、

Selenium::WebDriver::Error::TimeoutError が発生します。


発生したSelenium::WebDriver::Error::TimeoutErrorは、

  • 直下のrescueで補足される

と思っていたが、そうではなかった。


これに気づくのにめちゃくちゃ時間がかかりました笑


調べていくと、

  • wait.untilブロックの外側

にraiseされていました...


なので、下記のようにすれば捕捉出来ました。


修正したコード


def sample
  driver = Selenium::WebDriver.for :chrome

  # タイムアウトまでの時間
  wait = Selenium::WebDriver::Wait.new(timeout: 60)

  wait.until do
    driver.find_element(:id, 'search-result')&.displayed? # ここで例外が発生しても直下のrescueでは捕捉出来ない
  rescue Selenium::WebDriver::Error::TimeoutError => e
    raise Selenium::WebDriver::Error::NoSuchElementError
  rescue Selenium::WebDriver::Error::NoSuchElementError => e
    Rails.logger.error <<~EOS
      エラー
    EOS
    nil
  end

# 外側にrescueを追加。wait.untilブロック内で発生した例外は、ここにraiseされるのでここで捕捉出来る
rescue Selenium::WebDriver::Error::TimeoutError => e
    Rails.logger.error <<~EOS
      waitブロックでのエラー
      #{e}
    EOS
  nil
end


これでタイムアウトした場合も、

スクレイピングがエラーで止まってしまわないよう、

処理を継続するように出来ます。


例外処理は、

  • どこで発生しているのか

  • どこに投げられる(raiseされる)のか

  • どこで捕捉(rescue)出来るのか


これらを意識するのが大事ですね。




以上、

  • Seleniumの、wait.untilブロックでTimeoutしたら、waitの外側にraiseされる

についてでした。


少しでも同じ問題で困っている方の参考になれば幸いです。


このブログでは、僕がIT未経験から約1年でフリーランスエンジニアになるまでの過程、ノウハウなどを書いています。


  • フリーランスに興味がある

  • 今まさに活動している

という方は、下記の記事で、

  • 【実体験】高卒文系が1年でRailsのフリーエンジニアになった話

  • 【週3案件豊富 正社員並の保証】フリーランスエージェントMidworksを使ってみた感想

  • 【10倍効率化!?】プログラマの作業が鬼捗る【9つのグッズ】

を紹介していますので、よかったらチェックしてみてください。


www.malanka.tech

www.malanka.tech

www.malanka.tech






また、

駆け出しエンジニアに向けてのnoteを3月17日にリリースしました。

note.com


活躍出来るエンジニアになるためのマインドを、

ギュッと詰め込んだ、「実践型note」になってます。


  • 「IT転職を成功させたい!」

という方は是非チェックしてみてください。






最後までお読み頂きありがとうございました★

もしよかったらTwiiterのフォローもお願いします★