使用Selenium提交表单时出现StaleElementReferenceException错误

f0brbegy  于 2023-04-12  发布在  其他
关注(0)|答案(2)|浏览(282)

我尝试使用Selenium和Python在网页上提交表单。表单有一个输入字段和一个提交按钮,我尝试使用find_element()By.NAMEBy.XPATH定位。
我可以成功地在输入字段中输入文本并单击提交按钮。然而,在提交表单并被重定向到新页面后,我不断收到以下错误:

selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: element is not attached to the page document

据我所知,当我试图与之交互的元素不再存在于页面上时,就会发生此错误。然而,我很困惑为什么会发生这种情况,因为我已经成功地单击了提交按钮,并且表单已提交。
下面是相关代码:

import time
from selenium import webdriver
from selenium.webdriver.common.by import By

# open browser and go to webpage
driver = webdriver.Chrome()
driver.get('https://twitter.com/account/begin_password_reset')

# read usernames from txt file
with open('usernames.txt', 'r') as file:
    usernames = file.readlines()

# find input field and submit button
input_field = driver.find_element(By.NAME,'account_identifier')
submit_button = driver.find_element(By.XPATH,"//input[@type='submit' and @value='Search']")

# iterate over usernames and submit form
for username in usernames:
    # input username and submit form
    input_field.clear()
    input_field.send_keys(username)
    submit_button.click()

    # wait for form to submit
    time.sleep(10)

    # check if radio button exists and get label value
    try:
        label = driver.find_element_by_css_selector('input[name="method"][checked] + label')
        text = label.get_attribute('textContent')
        print(text)
    except:
        pass

# close browser
driver.quit()

谁能解释一下为什么我仍然得到这个错误,即使提交按钮被成功点击,表单被提交?有没有办法修复这个错误?
提前感谢您的帮助!
编辑(对于完整的错误日志):

Traceback (most recent call last):
  File "C:\Users\admin\AppData\Local\Programs\Python\Python311\tryreset.py", line 22, in <module>
    submit_button.click()
  File "C:\Users\admin\AppData\Local\Programs\Python\Python311\Lib\site-packages\selenium\webdriver\remote\webelement.py", line 93, in click
    self._execute(Command.CLICK_ELEMENT)
  File "C:\Users\admin\AppData\Local\Programs\Python\Python311\Lib\site-packages\selenium\webdriver\remote\webelement.py", line 410, in _execute
    return self._parent.execute(command, params)
  File "C:\Users\admin\AppData\Local\Programs\Python\Python311\Lib\site-packages\selenium\webdriver\remote\webdriver.py", line 444, in execute
    self.error_handler.check_response(response)
  File "C:\Users\admin\AppData\Local\Programs\Python\Python311\Lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 249, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: element is not attached to the page document
  (Session info: chrome=107.0.5304.107)
Stacktrace:
Backtrace:
    Ordinal0 [0x0082ACD3+2075859]
    Ordinal0 [0x007BEE61+1633889]
    Ordinal0 [0x006BB7BD+571325]
    Ordinal0 [0x006BE374+582516]
    Ordinal0 [0x006BE225+582181]
    Ordinal0 [0x006BE4C0+582848]
    Ordinal0 [0x006EC654+771668]
    Ordinal0 [0x006E1AED+727789]
    Ordinal0 [0x0070731C+881436]
    Ordinal0 [0x006E15BF+726463]
    Ordinal0 [0x00707534+881972]
    Ordinal0 [0x0071B56A+963946]
    Ordinal0 [0x00707136+880950]
    Ordinal0 [0x006DFEFD+720637]
    Ordinal0 [0x006E0F3F+724799]
    GetHandleVerifier [0x00ADEED2+2769538]
    GetHandleVerifier [0x00AD0D95+2711877]
    GetHandleVerifier [0x008BA03A+521194]
    GetHandleVerifier [0x008B8DA0+516432]
    Ordinal0 [0x007C682C+1665068]
    Ordinal0 [0x007CB128+1683752]
    Ordinal0 [0x007CB215+1683989]
    Ordinal0 [0x007D6484+1729668]
    BaseThreadInitThunk [0x771F00F9+25]
    RtlGetAppContainerNamedObjectPath [0x77337BBE+286]
    RtlGetAppContainerNamedObjectPath [0x77337B8E+238]
    ```
sg2wtvxw

sg2wtvxw1#

StaleElementReferenceException发生在您尝试与之交互的元素不再附加到DOM(文档对象模型)时,这意味着它已从页面中删除或被新的元素替换。
在您的例子中,当您尝试访问元素时,页面可能仍在加载或重定向到新页面的过程中,导致元素与DOM分离。
要修复此错误,您可以尝试在单击提交按钮后添加wait语句,以允许页面完全加载并将元素重新附加到DOM。您可以使用Selenium提供的WebDriverWait类来等待特定元素在页面上可用。
以下是如何修改代码以包含wait语句:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# iterate over usernames and submit form
    for username in usernames:
    # input username and submit form
    input_field.clear()
    input_field.send_keys(username)
    submit_button.click()

    # wait for form to submit and for page to fully load
    WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, 'input[name="method"][checked] + label')))

    # check if radio button exists and get label value
    try:
        label = driver.find_element_by_css_selector('input[name="method"][checked] + label')
        text = label.get_attribute('textContent')
        print(text)
    except:
        pass

在这段代码中,我使用WebDriverWait类等待长达10秒的时间,等待CSS选择器'input[name=“method”][checked] + label'的元素出现在页面上,然后继续执行。一旦找到元素,脚本将继续执行try块中的其余代码。
通过添加此wait语句,您应该能够避免StaleElementReferenceException错误,并按预期与元素交互。

whitzsjs

whitzsjs2#

问题是你在循环之前/之外获取和存储input_fieldsubmit_button。在循环内部,我敢肯定,当你点击提交按钮时,页面更改/刷新导致陈旧异常,因为你已经丢失了对这两个元素的引用。只要在循环内部获取这两个元素,就应该解决这个问题。一旦页面重新加载,这些元素是从当前页面中新获取的。
我还删除了循环中间的sleep。sleep是一个糟糕的做法,因为它们并不“聪明”。它们会等待你告诉它们等待的时间,这可能是足够的,也可能是太多的,这取决于网站的速度。相反,使用WebDriverWait来等待一些条件,它只会等待需要的时间,加快你的脚本速度,并(通常)消除间歇性问题。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

# open browser and go to webpage
driver = webdriver.Chrome()
driver.get('https://twitter.com/account/begin_password_reset')

# read usernames from txt file
with open('usernames.txt', 'r') as file:
    usernames = file.readlines()

# iterate over usernames and submit form
for username in usernames:
    # input username and submit form
    input_field = driver.find_element(By.NAME,'account_identifier')
    input_field.clear()
    input_field.send_keys(username)
    submit_button = driver.find_element(By.XPATH,"//input[@type='submit' and @value='Search']")
    submit_button.click()

    # wait for form to submit
    wait = WebDriverWait(driver, 10)
    wait.until(EC.staleness_of(submit_button))

    # check if radio button exists and get label value
    try:
        label = wait.until(EC.visibility_of_element_located(By.CSS_SELECTOR, 'input[name="method"][checked] + label'))
        text = label.get_attribute('textContent')
        print(text)
    except:
        pass

# close browser
driver.quit()

相关问题