こんにちは、ツバサです。
タイトルの通り、Pythonで下記例外が発生して困ったので備忘録として対処法を記録します。
selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: element is not attached to the page document
発生経緯
Amazonの購入履歴を取得するプログラムを書いていたときに、次の履歴ページへ遷移するために次のページをクリックすると発生しました。
その時のプログラムを抜粋するとこんな感じです。65行目のclick()で発生します。
# coding:utf-8
import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys # キー入力
from webdriver_manager.chrome import ChromeDriverManager # webdriver自動更新用
from getpass import getpass # パスワード入力
import csv # csv出力
def main():
user = "****@gmail.com" # ユーザID
print('user name is ' + user)
pw = getpass('input password:') # パスワード
# ログインページのURLとXpath
loginPage = {
'url':'https://www.amazon.co.jp/ap/signin?_encoding=UTF8&accountStatusPolicy=P1&openid.assoc_handle=jpflex&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.ns.pape=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Fpape%2F1.0&openid.pape.max_auth_age=0&openid.return_to=https%3A%2F%2Fwww.amazon.co.jp%2Fgp%2Fcss%2Forder-history%3Fie%3DUTF8%26ref_%3Dnav_AccountFlyout_orders&pageId=webcs-yourorder&showRmrMe=1',
'userForm':'/html/body/div[1]/div[1]/div[2]/div/div[2]/div/div[1]/form/div/div/div/div[1]/input[1]',
'pwForm':'/html/body/div[1]/div[1]/div[2]/div/div[2]/div/div/div/form/div/div[1]/input',
'nextButton':'/html/body/div[1]/div[1]/div[2]/div/div[2]/div/div[1]/form/div/div/div/div[2]/span/span/input',
'loginButton':'/html/body/div[1]/div[1]/div[2]/div/div[2]/div/div/div/form/div/div[2]/span/span/input'
}
driver = webdriver.Chrome(ChromeDriverManager().install()) # 1.webdriverを更新してChromeを起動
driver.implicitly_wait(10)
driver.get(loginPage['url'])
# ユーザID入力フォームを取得
userSelector = driver.find_element_by_xpath(loginPage['userForm'])
# ユーザID入力
print('Input user name.')
userSelector.send_keys(user)
# 次へボタンを取得(ID入力後、PW入力フォームへ進むためのボタン)
# ボタンがないサイトもあると思うのでない場合はスキップする
nextButtonSelector = driver.find_element_by_xpath(loginPage['nextButton'])
#次へボタン
if(len(loginPage['nextButton']) > 0):
print('Push next button.')
nextButtonSelector.click()
#pw入力フォームを取得
pwSelector = driver.find_element_by_xpath(loginPage['pwForm'])
#pw入力
print('Input password.')
pwSelector.send_keys(pw)
#ログインボタンを取得
loginButtonSelector = driver.find_element_by_xpath(loginPage['loginButton'])
#ログインボタン押下
print('Push login button.')
loginButtonSelector.click()
# セレクトボックス取得
select = driver.find_elements_by_xpath('//select[@name="orderFilter"]')
option = select[0].find_elements_by_tag_name('option')
option[2].click() #セレクトボックスの3つ目(2022年)をクリックして履歴の件数変更
# ページングのボタンを取得する
ul = driver.find_elements_by_xpath('//ul[@class="a-pagination"]') # ボタン群
li = ul[0].find_elements_by_tag_name("li")
nextButtonNum = len(li)
# 前へボタンと次へボタンを省いた数分ループ
# 1ページずつ履歴を取得していく
for i in range(2,nextButtonNum,1):
li[i].click() # 次のページへ移動
#待機(確認用)
time.sleep(5)
main()
原因
ページ遷移することで取得したページングボタンの値(58~60行目)が消えてしまうようです。
なので消えてしまった値を再度取得すればOKです。修正したfor文を記載します。
for i in range(2,nextButtonNum,1):
li[i].click() # 次のページへ移動
# 再取得。これでエラー回避
ul = driver.find_elements_by_xpath('//ul[@class="a-pagination"]') # ボタン群
li = ul[0].find_elements_by_tag_name("li")
nextButtonNum = len(li)
最後に
まだまだSeleniumに慣れていないのでこういった不慣れなエラーは随時記録して、エラー原因をある程度予測できるようにしていきたいですね。
以上!最後までご覧いただきありがとうございました!
コメント