先日MENTAでスクレイピングの相談を受けていたのですが、先日デベロッパツールで存在する要素を指定したのにSeleniumでアクセスしようとすると「no such element: Unable to locate element」というエラーが出るという質問を頂いたので、その時の解答をメモしておきます。
Contents
まずページソースを見る
基本的にデベロッパツールでは要素が表示されているのにSeleniumでその要素のxpathなんかを指定すると「no such element: Unable to locate element」が出るときはまずSeleniumのドライバーが読み込んでいるHTMLを確認しましょう。
こういう場合はSeleniumがサイト側のBOT検知に引っかかって403のエラーメッセージが返されていたり、JSであとから非同期処理で返されているHTML部分を読み込めていないケースが多いです。
Seleniumのドライバーが読み込んでいるHTMLは以下で確認できます。
# ドライバーが読み込んでいるHTMLを出力する print(driver.page_source)
要素が取得できない場合のよくある原因
①Javascriptの非同期処理で返されるHTMLを取得出来ていない
よくあるのが、HTMLがJavascriptによって非同期で生成されていて、それが取得できていないパターンです。これはモダンなECサイトなんかでよくあります。この手のサイトはサイトにアクセスした瞬間には商品の情報などはまだ表示されておらず、あとから非同期処理で商品の情報を表示していることが多いです。
こういう場合はSeleniumでアクセスしてもすぐ要素が生成されていないので、Seleniumで高速で要素を指定すると、サイト側のJSによるHTML生成が追いついておらず取得したい部分のHTML要素がまだ生成されていないため「no such element: Unable to locate element」になるパターンがあります。
こういう場合はプログラムの実行をサイト側がHTMLを生成するまでtime.sleepなどで待機する必要があります。
<解決例イメージ>
~~ import time driver = webdriver.Chrome(/driver,desired_capabilities=d) driver.get(url) # 次のプログラムの実行を数秒待つ time.sleep(5) check1 = driver.find_element_by_xpath("/html/body/~~/input") check1.click()
②webページにワイヤーフレームが使われている
2つ目はWEBページにワイヤーフレームが使われているパターンです。
ワイヤーフレームとは:https://nandemo-nobiru.com/web-5695
これだとフレームごとにHTMLが完全に分割されているので、デベロッパツールから見たXPATHや要素をそのまま指定してもアクセスできません。解決法はサイトのIframeタグからフレーム名を特定してフレームを切り替えることです。
# フレームを切り替える driver.switch_to.frame('フレーム名') # 一番上のコンテンツに戻る driver.switch_to.default_content()
この際フレームとフレームの間に連携はないので、フレーム内から別のフレームのHTML要素にアクセスしようとするとエラーになるので、driver.switch_to.default_content()
でサイトで一番上にあるフレームに都度戻る必要があります。
関連記事:【Python】Seleniumでiframe(インラインフレーム)にハマった話
③スクレイピングがばれてIPが弾かれている
最後がシンプルにサイト側にスクレイピングがバレていて、IPがブロックされていることでHTMLが正常に取得出来ていないパターン、この場合はTorなどでIPを切り替える必要があります。
関連記事:【Python】SeleniumでTor経由でIPを切り替えつつスクレイピングする
関連記事:【Python】Requestsでサイトをスクレイピングした時に403エラーが返された時の解決策
終わり~参考書紹介
コメント
[…] 関連記事:Seleniumで「no such element: Unable to locate element」が出る原因 […]