Python/Selenium:要素はあるのにNoSuchElementExceptionが出る

- Python -
2024.01.04
Python[パイソン]

Python・Seleniumで作ったとあるプログラム。

こんな状況に出くわしました↓

  • 毎日普通に動いていた
  • ある日「NoSuchElementException・no such element」、つまり「そんな要素ないよ」と怒られ動かなくなった
  • HTML構造を見ると、確実にその要素はある
  • でもエラーが続く。要素が取れない

念の為、出ていたエラーはこれ↓。

selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"li.categoryItem:nth-child(3)"}

同じような状況におちいっているかたへ向けて「こうしたらとりあえず直った」という方法をメモしておきます。

結論、

WebDriverWaitモジュールを使って明示的に待機を指示する

ことで動くようになりました。

まだ要素が描画される前に取得しようとしていたようです(それまで全く問題なく動いていたので100%納得はできていませんが)。

ちなみに:

「要素はあるけど描画が遅れる」対策で、

driver.implicitly_wait(30)

のように待機指示を書いていましたがダメでWebDriverWaitを使ってさらに明示的な待機を指示したら直りました。

Selenium:要素はあるのにNoSuchElementExceptionが出る

以下、これをこう書き換えたら直った例です。

▼BEFORE

Pythonfrom webdriver_manager.chrome import ChromeDriverManager
from selenium import webdriver

driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get('xxx URL xxx')
elem_text = driver.find_element_by_class_name('category').text

▼AFTER

Pythonfrom webdriver_manager.chrome import ChromeDriverManager
from selenium import webdriver
# ▼追加
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get('xxx URL xxx')
# ▼こんな感じで書き換え
elem_text = WebDriverWait(driver, 30).until(EC.presence_of_element_located((By.CLASS_NAME, 'category'))).text

ちなみに:

上記コードは、chromedriverの更新を自動化するwebdriver_managerという便利ライブラリを使っています。

参考記事【Selenium】ChromeDriver自動更新で楽する方法【Python】

AFTER 11行目は、

WebDriverWait(driver, 30)
→ 30秒待て

.until(EC.presence_of_element_located((By.CLASS_NAME, 'category')))
→ "category"というクラス名の要素がDOM上に現れるまで

...という意味です。

EC.presence_of_element_located((By.CLASS_NAME,〜の部分は、

  • EC.element_to_be_clickable((By.ID, 〜
    → idで指定した要素がクリック可能な状態になるまで待つ
  • EC.presence_of_all_elements_located((By.CSS_SELECTOR, 〜
    → CSSセレクタで指定した全ての要素がDOM上に現れるまで待つ

のように状況に応じたバリエーションが用意されています。

そのあたりのWebDriverWaitモジュールをざっと把握するには以下を参考にどうぞ。

参考サイト明示的な待機 — Selenium Python Bindings 2 ドキュメント

 

▼体型的なスクレイピング学習におすすめ

技術評論社Pythonクローリング&スクレイピング[増補改訂版] -データ収集・解析のための実践開発ガイド
Amazonで見る ≫
↑TOP