Selenium for Python 等待具有动态内容的元素的条件

问题描述 投票:0回答:2

我正在尝试用一些脚本帮助朋友在他们用于计费的某些网站上自动计费保险。我正在使用 Selenium Webdriver 和 Python。该过程需要从下拉菜单中选择选项,其中许多是在加载页面时创建的,但会根据用户在其他字段中所做的选择进行填充。

我认为这种动态的字段填充是代码崩溃的原因,即使我写的是这样的:

WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, 'an_ID'))).click()

我得到错误:

Exception has occurred: StaleElementReferenceException
Message: stale element reference: element is not attached to the page document

但是如果我在调试模式下逐行执行代码,一切都运行良好(我逐步执行的速度足够慢,所有内容都可以正确加载)。这让我认为该元素很早就存在并满足等待条件,但内容还不存在或类似的东西。

我可以通过强制代码等待来解决问题,例如,使用

time.sleep(2)
,但我实际上必须为每个元素都这样做,而且由于各种原因,从代码可读性到运行时,这似乎是错误的,等等

为内容中的元素寻找 ID 似乎也行不通,因为内容是动态的,我不确定 ID 是否可以在会话中保持相同。

我是Selenium的新手,所以我想知道是否有更合适的方法。 如果你们有好的建议(我只能找到基本的),我也很乐意自助阅读一些关于 Selenium 的高级教程/书籍。

谢谢!

python selenium-webdriver webdriverwait
2个回答
0
投票

您可以使用 Selenium 中的 expected_conditions 库来定义这些条件。

wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.ID, 'an_ID')))

wait = WebDriverWait(driver, 10)
# Find the element
element = wait.until(EC.presence_of_element_located((By.ID, 'an_ID')))

# Refresh the element to ensure it's attached to the DOM
driver.execute_script("arguments[0].scrollIntoView();", element)
driver.execute_script("arguments[0].click();", element)

driver.implicitly_wait(10)

Selenium 在抛出 NoSuchElementException 之前等待每个 find_element 方法调用最多 10 秒。如果您的代码中有很多 find_element 调用并且不想为每个调用添加显式等待,这将很有用。


0
投票

你的陈述

这让我觉得元素早就存在并且满足了等待条件,但内容还没有存在或类似的东西。

可能完全正确。因为您从导致页面重新加载的下拉列表中选择一个选项,所以很可能满足您的等待条件,但在执行操作的过程中,元素引用变得陈旧。

有一个简单的方法可以解决这个问题。在重新加载页面的操作之后,您需要等待所选元素过时。步骤是:

  1. 获取并存储对要单击的元素的引用(例如
    button
    ),这将更改/重新加载页面
  2. 点击
    button
  3. 等待
    button
    变得陈旧使用
    EC.staleness_of(button)
    表明页面已经开始重新加载
  4. 继续脚本

每次你要执行一些更改/更新页面的操作时,你基本上都会重复这个过程。

这里是一些示例代码

wait = WebDriverWait(driver, 10)
button = wait.until(EC.element_to_be_clickable((By.ID, 'an_ID'))); # store the reference to the element we're about to click
button.click() # this click reloads/changes the page
wait.until(EC.staleness_of(button)) # wait for the reference to go stale
button = wait.until(EC.element_to_be_clickable((By.ID, 'some_other_ID'))).click();
# proceed with the rest of the script

注意:根据文档,您不应混合隐式和显式 (

WebDriverWait
) 等待。您应该删除隐式等待,并在需要时重复使用
WebDriverWait

© www.soinside.com 2019 - 2024. All rights reserved.