[Selenium Ruby] Element is not currently interactable and may not be manipulatedのエラー
Seleniumでウェブブラウザの操作を自動化しています。社内システムや航空会社の予約システム等のウェブサービスの煩雑な操作のオートメーションに絶大な力を発揮するので感動しているのですが、webページの読み込みのタイミングによっては、たまに以下のような「Element is not currently interactable and may not be manipulated」エラーが出ることがあります。
gems/ selenium-webdriver-2.43.0/lib/selenium/webdriver/safari/bridge.rb:73: in `raw_execute': Element is not currently interactable and may not be manipulated (Selenium::WebDriver::Error::InvalidElementStateError) from gems/selenium-webdriver-2.43.0/lib/selenium/webdriver/remote/bridge.rb:616:in `execute' from gems/selenium-webdriver-2.43.0/lib/selenium/webdriver/remote/bridge.rb:415:in `sendKeysToElement' from gems/selenium-webdriver-2.43.0/lib/selenium/webdriver/common/element.rb:126:in `send_keys' from show_kaikei_rs.rb:39:in `sendKey' from show_kaikei_rs.rb:81:in `'
もちろん、エレメントの操作(clickやsend_keys)の前には、以下のように要素が存在することを確認するwait.untilを入れています。
1
2
3
4
5
6
def click(xpath)
@wait.until {
@driver.find_element(:xpath, xpath) != nil
}
@driver.find_element(:xpath, xpath).click()
end
原因を調べてみると、社内システム等では「画面の全ての要素がダウンロードされ表示可能になるまで、要素のコントロールを禁止する」ためのJavascriptが動いていることがあるようです。
全要素がダウンロードされ表示されていることの確認は結構ややこしいので、安直には、操作対象のエレメントに対するwait.untilの後、十分長い(5秒とか)sleepを入れてからclick()等を実行するようにしています。
つまり、以下のようなfind()を用意しておいて、
1
2
3
4
5
6
7
8
9
10
def find(xpath)
begin
@wait.until {
@driver.find_element(:xpath, xpath) != nil
}
return @driver.find_element(:xpath, xpath)
rescue
return nil
end
end
find()で操作対象のエレメントが存在することが確認できたあと、sleep 5とかしてclickしています。
1
2
3
4
5
6
7
xpath="//input[@value='登 録']"
if(find(xpath)!=nil)then #操作対象のinputが登場するまで待って、
sleep 5 #さらに他の全要素が読み込まれるまで十分(この場合5秒)待ってから
click(xpath) #操作対象をclick()
else
#エラー処理
end
関連情報:
Qiita - RubyでSeleniumを使ってスクレイピング
酒と泪とRubyとRailsと - Seleniumでスクレイピング