在Selenium Python自动化测试场景中,动态元素指的是页面加载完成后不会立刻出现,或者属性值会动态变化的元素,比如异步加载的列表项、点击按钮后弹出的弹窗、滚动后加载的内容等。这类元素如果直接用常规的find_element方法定位,很容易因为元素还未渲染完成而抛出NoSuchElementException异常,导致脚本运行失败。

常见的动态元素场景
实际测试中遇到的动态元素通常可以分为以下几类:
- 异步接口返回后渲染的元素,比如电商页面的商品列表,需要等待接口请求完成才会显示
- 用户交互后触发的元素,比如点击提交按钮后出现的提示弹窗、下拉菜单展开的选项
- 属性动态变化的元素,比如倒计时组件的文本、进度条的百分比数值,每次刷新都会变化
- 懒加载元素,比如长页面滚动到对应位置才会加载的图片、内容块
显式等待的核心原理
显式等待是Selenium提供的智能等待方式,它会创建一个WebDriverWait实例,指定最大等待时间和轮询间隔,然后在最大等待时间内不断检查传入的条件是否满足,一旦满足条件就立刻返回对应元素,超过最大等待时间仍未满足则抛出TimeoutException。
和强制等待(time.sleep)相比,显式等待不会固定阻塞脚本,满足条件就立刻继续,既提升了脚本执行效率,也避免了等待时间不足导致的报错。和隐式等待相比,显式等待可以针对单个元素设置不同的等待条件,灵活性更高。
显式等待的基本使用
使用显式等待需要先导入对应的模块,基本步骤如下:
- 导入WebDriverWait类和expected_conditions模块
- 创建WebDriverWait对象,传入driver实例和最大等待时间(单位:秒)
- 调用until方法,传入预期条件,获取对应的元素或结果
下面是一个基础的使用示例,等待页面中id为dynamic_content的元素出现:
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()
driver.get("http://ipipp.com/dynamic_page")
# 创建显式等待对象,最大等待10秒,默认每0.5秒检查一次条件
wait = WebDriverWait(driver, 10)
# 等待id为dynamic_content的元素出现,出现后返回该元素
dynamic_element = wait.until(
EC.presence_of_element_located((By.ID, "dynamic_content"))
)
# 后续操作,比如点击该元素
dynamic_element.click()
driver.quit()
常用的预期条件
expected_conditions模块提供了很多内置的预期条件,覆盖了大部分动态元素的处理场景,常用的有以下几种:
| 预期条件 | 说明 |
|---|---|
| presence_of_element_located | 等待元素出现在DOM中,不要求可见 |
| visibility_of_element_located | 等待元素出现在DOM中且可见(宽高大于0) |
| element_to_be_clickable | 等待元素可见且可点击 |
| text_to_be_present_in_element | 等待元素的文本中包含指定内容 |
| invisibility_of_element_located | 等待元素不可见或者从DOM中移除 |
| element_located_to_be_selected | 等待元素处于选中状态 |
比如等待一个按钮可点击的场景,就可以使用element_to_be_clickable条件:
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
# 等待class为submit_btn的按钮可点击,最多等10秒
submit_btn = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.CLASS_NAME, "submit_btn"))
)
submit_btn.click()
自定义预期条件
如果内置的预期条件无法满足需求,还可以自定义预期条件。自定义条件只需要是一个可调用对象,接收driver作为参数,返回对应的检查结果即可。比如需要等待某个元素的value属性等于指定值,可以这样实现:
from selenium.webdriver.support.ui import WebDriverWait
# 自定义预期条件,检查元素的value属性是否等于目标值
def element_value_equal(locator, target_value):
def check(driver):
element = driver.find_element(*locator)
return element.get_attribute("value") == target_value
return check
# 使用自定义条件,等待name为username的输入框value等于test_user
WebDriverWait(driver, 10).until(
element_value_equal((By.NAME, "username"), "test_user")
)
注意事项
使用显式等待处理动态元素时,需要注意以下几点:
- 显式等待和隐式等待不要混合使用,两者同时设置可能会导致等待时间不可控,出现意外的等待时长
- 最大等待时间不要设置过长,一般根据元素的实际加载情况设置3-15秒即可,避免脚本执行效率过低
- 如果元素定位表达式本身有问题,显式等待也会一直检查到超时,所以首先要确保元素的定位表达式是正确的
- 处理动态变化的属性时,不要使用固定的属性值定位,优先使用id、name等稳定的属性,或者使用XPath的contains方法匹配部分属性值
合理运用显式等待,可以有效解决Selenium Python自动化中绝大多数动态元素的处理问题,让自动化脚本更加稳定可靠。