seleniumで要素を取得したいけど、うまく取れない!
「そんな要素は存在しません」とエラーが出る、なんでや!
ということは僕自身しょっちゅう発生しますが、ここは気持ちを落ち着かせて、これから紹介する原因を疑ってみて下さい。
今回は、seleniumで要素が取得できない時に疑うべき項目を6つ紹介します。
タイプミスを疑う
経験的にコレが一番多いです。
” driver.find “を” driver_find “のように細かい部分を間違えていないかしっかり見直しましょう。
また、class_nameと指定したのにselectorを入れた、xpathって書いたのにclassを入れたということも、コードが長くなるにつれて多くなるので、コピペをするときはしっかり確認するようにしましょう。
扱ってるデータ型を疑う
seleniumはリストや文字列など様々なデータ型を扱います。
特にボクがミスするのは.textを入れ忘れる、またはfind_elementsに.textを入れることです。
例えば画面に”今日は晴れです。”という文字が入っている要素を指定したいとき、
driver.find_element_by_class_name("todaysweather") == "今日の天気は晴れです。"
と書いてしまうとエラーが出ます。ここは
driver.find_element_by_class_name("todaysweather").text == "今日の天気は晴れです。"
と書くことで無事に”今日の天気は晴れです。”と書いてTrueが返ってきます。また多いのが、
apple = driver.find_elements_by_class_name("apple")
print(apple.text)
と書き間違えることが多いです。
find_elementsで取得した値はリストになっているので、print(apple)と書くとリストが返ってくるだけでなく、よもや.textと文字列をリクエストするとエラーを吐きます。よって、
apple = driver.find_elements_by_class_name("apple")
for i in apple:
print(i.text)
という風に、for文で一つ一つ処理をしなければいけません。
このようにseleniumは指定の仕方でデータ型が変わり、それに合わせて処理を変えないといけませんので、しっかり自分が何を取得したのか把握しておかなくてはいけません。
クラスが2つ混ざっていないか疑う
htmlを書いたことがある人ならば分かると思いますが、htmlのクラス名は一つとは限りません。二つ以上のクラス名が含まれていることは頻繁にあります。
それを確認せず全てコピペして” driver.find_element_by_class_name “に入れるとエラーが出ます。class_nameは2つのクラス名を受け付けないからです。
クラス名が2つある場合はhtmlにはスペースが入れられています。もし入れられていたら必要な方を指定してください。
自動操作がダイアログに阻まれてないか疑う
何気なく押しているダイアログも、自動操作をする際には敵になりえます。
ヘッドレスでseleniumを起動させて、いつも同じ部分で引っ掛かることに気づき、調べたらダイアログが発生しているという事があります。ログインの時やページを移動するときに多い気がします。
しかし、seleniumはダイアログを操作する機能を持っているので、これを乗り越えることが出来ます。
from selenium.webdriver.common.alert import Alert
try:
Alert(driver).accept()
except:
pass
アラートを扱うために専用のモジュールをインポートし、accept()など処理を施すことでダイアログのボタンを押すことが出来ます。
ポップアップウィンドウが発生してないか疑う
宣伝などで使われるポップアップウィンドウは、場合によって出たり出なかったりします。
しかし、厄介なのはseleniumはポップアップウィンドウの操作が出来ないという事です。
この場合はどうすればよいのか、諦めるしかないのか。いろいろ試してみた結果、どうも画面の更新で乗り切れるっぽいです。
ですので、もしポップアップで操作が阻まれている場合は、seleniumで更新の操作を試してみましょう。
iframeのDOM構造を疑う
seleniumは、iframe要素の中にあるDOMはそのままだとアクセスできません。
実際にbet365というサイトでも同様の例で見つかりました。
この場合、iframeにdriverを切り替えることで標準では押せなかったボタンが操作できるようになります。
iframe = driver.find_element_by_class_name("class-name")
buttom = driver.switch_to_frame(iframe)
buttom.click()
Can’t I select an iframe in selenium?
まとめ
タイプミスから技術的なことまで合計6つの原因を検証しました。
これらすべてを検証すればほとんどの値は取得できるので、諦めず楽しいseleniumライフを送って下さい!笑