【selenium】find_elementで要素が取得できない・エラーになる原因とその対処法

Python

今回は、Seleniumのfind_elementメソッドで要素がうまく取れない場合の対処法について解説します。

はじめに

Seleniumのfind_elementメソッドでHTMLの要素を取得しようとした際に、取得したい要素とは違うものが取得されたり、InvalidSelectorExceptionやNoSuchElementExceptionなどのエラーが発生することがあります。

エラーの原因は実に様々で、スペルミスや指定方法の誤りなどの軽微なものから、JavaScriptやiframe等が原因である場合など、一概にエラーといっても対応方法が異なってきます。とはいえ、なかなか原因を特定するのは難しかったりするので、自分が遭遇したエラーや問題点をまとめておこうと思いました。

Seleniumはテスト自動化・スクレイピングなどの用途で使用され、find_elementを使う機会も多いかと思います。原因別・深刻度別に対処法をまとめましたので、参考になれば幸いです。

【原因1】要素名の指定が間違っている

深刻度:★☆☆☆☆

古い書き方をしている

「findElementByXXX(“XXX”)」は、Seleniumのバージョンが4以上の場合使用できません。

◆古い書き方(バージョン3まで)
driver.findElementByClassName("className");
◆現在の書き方(バージョン4)
driver.findElement(By.className("className"));

参考:Selenium4にアップグレードする方法

クラス名に半角スペースが入っている

Seleniumでは、以下のようにクラス名に半角スペースが入っている場合は、クラス名を羅列しているとみなされます。

driver.findElement(By.className("class Name"));

上記の場合、「class」「Name」どちらもクラス名に持つ要素が取得されます。該当する要素がない場合、InvalidSelectorExceptionが発生します。

対処法としては、XPathやCSSセレクタなど、クラス名以外で要素を指定します。

指定した要素名が複数あって取れていない

HTML内に同じ要素名が複数ある場合があります。例えば、テーブルの場合は以下のように複数のデータがテーブル内に存在します。

このとき、find_elementを使うと、指定した要素名に一致する最初の要素しか取得できません。

対応策としては、find_elementsで要素名に一致するもの全てをリストで取得して、リストの中身を取り出します。

elements = driver.findElements(By.className("className"));
elem = elements[1];     # 2番目の要素を取得

参考:Selenium公式ドキュメント>Web要素の検索

上記対応でもエラー(NoSuchElementException)が発生している場合、後述の対応策を参照してください。

【原因2】要素が何らかの原因で隠れている/表示されていない

深刻度:★★☆☆☆

要素がなんらかの原因で隠れていたり、表示されていない場合は、「Element is not clickable at point」やNoSuchElementException等のエラーが発生し取得に失敗します。

原因対策
ポップアップが表示されていて
要素が隠れてしまっている
1.開いてすぐポップアップが表示される場合は、ウインドウ切替
2.ポップアップが必ず出るわけではない場合、Javascript実行
画面上に操作したい要素が
表示されていない
1.要素がある位置までページをスクロールする
  例) element.send_keys(Keys.PAGE_DOWN)
2.ウインドウを最大化する
  例) driver.maximize_window()
まだ要素が表示されていないページが表示されるまで待機する
  例) time.sleep(3) #3秒待つ
ログインが必要な画面ログイン処理を追加する
ベーシック認証が必要な画面ブラウザ起動時にユーザー・パスワードを渡す
ユーザー:username / パスワード:passwordの場合
driver.get(“https://username:password@test.com”)

画面のスクロール・最大化は以下のようにして行うこともできます。

# 垂直方向に1000ピクセルスクロール
driver.execute_script('window.scrollBy(0, 1000);')

# 最下部へスクロール
driver.execute_script('window.scrollTo(0, document.body.scrollHeight);')

# 全画面表示
driver.maximize_window()

iframeJavaScriptでの要素取得については、後述します(リンクから飛べます)。

【原因3】iframe内の要素を取得しようとしている

深刻度:★★★☆☆

要素がiframeになっていると、エラー(NoSuchElementException)が発生します。

そもそもiframeって?

iframe(アイフレーム)とは、「インラインフレーム」とも呼ばれるHTMLタグのひとつです。iframeは、TwitterやYoutubeの埋め込みなど、別のWebページを表示する際に使われます。

以下は、当ブログの記事内Youtubeを埋め込んだ例です。

そして、以下が該当部分のHTMLです。

<iframe>というタグ内にYoutubeの動画URLが記載されています。このように、Webページ内に別のWebページを埋め込む際に使われます。最近のWebサイトだとけっこう多いです。

iframeかどうかを確認する

開発者ツールの検索窓(Ctrl + F)に「iframe」と入力します。

使用されていたら、以下手順で要素を取得します。

iframe内の要素の取得方法

nameで指定する場合

<iframe name=frameName></iframe>

iframeにname属性が設定されている場合は、nameを指定して対象のフレームに切り替えます。

driver.switch_to.frame('frameName')

インデックスを使う場合

iframeのn番目を指定して切り替えることも可能です。iframeが複数ある場合に便利です。

driver.switch_to.frame(1)

xpathを使う場合

iframe = driver.find_element(By.XPATH, 'iframeのxpath')
driver.switch_to.frame(iframe)

参考:Selenium公式ドキュメント>IFrame と Frame の操作

【原因4】javascript要素を取得しようとしている

深刻度:★★★★☆

要素がJavaScriptになっていると、エラー(NoSuchElementException)が発生します。

JavaScriptは、Webサイトに動的な処理を加えるはたらきをしています。

JavaScriptの例
  • 画面にポップアップを表示する
  • 動きのあるページの作成(画像がスライドする、アニメーションなど)

JavaScriptかどうかを確認する

開発者ツールの検索窓(Ctrl + F)に「javascript」と入力します。

以下は、日本標準時刻を提供するサイトです。「content=”text/javascript”」という記述があります。

また、以下はボタンクリック時にJavaScriptが実行されるようになっているボタンです。

取得したい要素に、javascriptという記述が含まれている場合はJavasScriptが使われている可能性が高いです。

ポップアップが出る場合の対処法

ポップアップが出て要素が取得できないという場合は、execute_scriptメソッドを用いてJavaScriptを実行します。

js = "document.getElementsByClassName('ClassName').click()"
driver.execute_script(js)

ボタンがJavaScriptになっている場合の対処法

ボタンがJavaScriptになっている場合は、onclickイベントを指定することで実行できます。

<a href="javascript:void(0);" onclick="javascript:$('form').submit();" class="class1">
      <span>ログイン</span>
</a>
driver.execute_script("javascript:$('form').submit();")

【原因5】スクレイピングを禁止されている

深刻度:★★★★

短時間に大量のアクセスを行うと、IPアドレスでブロックされることがあります。(HTTPError:403エラー)

この場合、TorなどでIPアドレスを偽装するか、諦めるしかないです。サイトによっては時間が経てば制限が解除される場合もあるので、少し時間をおいてから試してみても良いかと思います。

取得しようとしているWebサイトが、そもそもスクレイピングを禁止している場合もありますので、スクレイピング実施前に確認しておくことをおすすめします(過去記事参照)。

まとめ

今回は、Seleniumのfind_elementメソッドがうまくいかない・エラーになる原因とその対処法を紹介しました。

私が一番つまづいたのはiframeでした。全然気づかず「ifame」というワードすら浮かんでなかったので、しばらくハマってしまいました。。。テーブルやリストなどHTMLの中身の解析に関しては、BeautifulSoupを使ったほうが良いかなと思います。

Seleniumは、Webdriverの他に「Selenium IDE」というブラウザ拡張機能も存在します。プログラミングなしで自動化を行いたい場合におすすめです。

chaso

文系出身、数字が苦手な平凡主婦。塾講師、大手企業SE、不動産事務、Webライター、結婚後はパートタイムでエンジニアをしています。機械音痴だけど効率化や自動化をこよなく愛しています!お仕事の依頼・ご相談は問い合わせよりお願いいたします♪

chasoをフォローする

コメント

タイトルとURLをコピーしました