目次
目的
私がSeleniumを使用していてハマったエラーをメモ程度に記載
StaleElementReferenceException
発生したソース
ある複数ある要素を取得し、for分で回す。
その中で別タブを開き処理完了したら、開いたタブを閉じ、次のループ処理をするようなもの。
item_link = item.find_element_by_tag_name("a").get_attribute("href")
この部分でStaleElementReferenceExceptionが発生した。
しかも毎回決まった要素で発生するわけではなく、ランダム。
for item in browser.find_element_by_class_name("items-box-content").find_elements_by_class_name("items-box"):
item_link = item.find_element_by_tag_name("a").get_attribute("href")
browser.execute_script("window.open()") #新しいタブを作成
browser.switch_to.window(browser.window_handles[-1]) #新しいタブに切り替え
browser.get(item_link)
__wait_browser(browser)
if len(browser.find_elements_by_class_name("deleted-item-name")) > 0:
# 商品が削除されている
browser.close()
browser.switch_to.window(browser.window_handles[1])
continue
原因
StaleElementReferenceExceptionは参照していた要素が古くなった
例えば、商品一覧のページで商品一覧のDOMを取得し、処理をしている間に更に商品が追加されたとか
かなと勝手に思っている。
解決策
再定義してやればいいらしい。
wait.until(ExpectedConditions.stalenessOf(whatever element));
参考:How to avoid StaleElementReferenceException in Selenium - Python
まあ、私はうまくいかなかったので以下のitemを使用するのを止めた
for分の中で再度、要素を探して定義している。
有識者からしたらブチ切れ案件かと思いますが、Exceptionは吐かなくなったのでおkおk。
誰かに渡すわけでもないし。
for item in browser.find_element_by_class_name("items-box-content").find_elements_by_class_name("items-box"): # 商品単体
item_link = ""
item_link = browser.find_element_by_class_name("items-box-content").find_elements_by_class_name("items-box")[index].find_element_by_tag_name("a").get_attribute("href")
index += 1
browser.execute_script("window.open()") #新しいタブを作成
browser.switch_to.window(browser.window_handles[-1]) #新しいタブに切り替え
browser.get(item_link)
__wait_browser(browser)
if len(browser.find_elements_by_class_name("deleted-item-name")) > 0:
# 商品が削除されている
browser.close()
browser.switch_to.window(browser.window_handles[1])
continue
NoSuchElementException
原因
NoSuchElementExceptionはその名の通り指定した要素が無いときに起きるエラー。
ページが読み込み終わっていないのに要素を取得だったり
私は起きたことないが、seleniumの画面に映っていない要素に対してアクションしようとすると起こったりするらしい。
あとは遷移したつもりでいたが、遷移できていないとか。
解決策
基本は待機処理入れておけばいい。
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ECWebDriverWait(browser, 15).until(EC.presence_of_all_elements_located)
上記は画面全体がロードするまで待つ。
15秒過ぎてもロードできなければタイムアウトエラー。
指定の要素のみがロードされるまで待機するなら以下のように書けばよい。
"chatframe"というIDが読み込まれるまで待機
WebDriverWait(browser, 15).until(EC.presence_of_element_located((By.ID,"chatframe")))
javascriptを実行しないと要素が取得できない場合は
browser.execute_script("javascript:document.frmomikuji.submit();")
みたいな感じjavascriptを実行することができる
InvalidSelectorException
原因
webdriver.find_element_by_class_name("//div[@class=\"a-section a-spacing-double-large\"]")
上記のようにfind_element_by_class_nameに対してxpathの書き方をしていた。
解決策
webdriver.find_element_by_xpath("//div[@class=\"a-section a-spacing-double-large\"]")
とすることで起きなくなった
まとめ
他にあれば随時更新していく
単純作業にお悩みではありませんか?
何百とあるワードを検索してファイルにまとめたり 数ある商品情報から条件にあるものだけ目で探してリ...
その単純作業プログラムで解決できるかもしれません。 もしよろしければ単純作業からの解放をお手伝いさせてください。
詳しくは以下のページからDM、または見積もり相談お願い致します。