一、为什么需要等待机制?

网页是动态加载的,元素出现的时间不确定。如果脚本在元素还没加载完成时就尝试操作它,就会抛出 NoSuchElementException 异常。

三种等待方式:

  1. 强制等待time.sleep() - 简单但低效

  2. 隐式等待driver.implicitly_wait() - 全局设置

  3. 显式等待WebDriverWait + expected_conditions - 最推荐的方式


二、强制等待 (不推荐但需了解)

import timetime.sleep(5) # 强制等待5秒
  • 优点:简单易用

  • 缺点

    • 效率低下(总是等待固定时间)

    • 不可靠(网络慢时可能不够,网络快时浪费時間)


三、隐式等待 (Implicit Wait)

设置一个全局的等待时间,对所有元素查找操作都生效。

from selenium import webdriverdriver = webdriver.Chrome()
driver.implicitly_wait(10) # 设置隐式等待时间为10秒driver.get("https://example.com")
# 所有find_element操作都会最多等待10秒
element = driver.find_element(By.ID, "some-element")
  • 工作原理:在查找元素时,如果立即没找到,会轮询DOM直到找到元素或超时

  • 优点:一次设置,全局生效

  • 缺点

    • 不够灵活,无法针对特定条件等待

    • 可能会影响脚本性能


四、显式等待 (Explicit Wait) - 重点推荐

显式等待允许你设置特定条件,只在需要的地方等待,更加灵活和高效。

1. 基本用法

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By# 创建WebDriverWait实例,设置最长等待时间10秒
wait = WebDriverWait(driver, 10)# 等待直到元素可见
element = wait.until(EC.visibility_of_element_located((By.ID, "myDynamicElement")))# 等待直到元素可点击
element = wait.until(EC.element_to_be_clickable((By.ID, "submit-btn")))# 然后进行操作
element.click()

2. 常用的 Expected Conditions

Selenium 提供了许多预定义的条件,以下是最常用的几种:

元素存在与可见性
  • presence_of_element_located(locator) - 元素出现在DOM中(不一定可见)

  • visibility_of_element_located(locator) - 元素可见(有宽度和高度)

  • invisibility_of_element_located(locator) - 元素不可见或不存在

元素可交互性
  • element_to_be_clickable(locator) - 元素可见且可点击

  • element_to_be_selected(locator) - 复选框/单选框可被选中

文本内容
  • text_to_be_present_in_element(locator, text) - 元素包含特定文本

  • text_to_be_present_in_element_value(locator, text) - 元素的value属性包含特定文本

页面状态
  • title_is(title) - 页面标题完全匹配

  • title_contains(partial_title) - 页面标题包含特定文本

  • url_to_be(url) - URL完全匹配

  • url_contains(partial_url) - URL包含特定文本

元素选择状态
  • element_located_to_be_selected(locator) - 元素被选中

  • element_located_selection_state_to_be(locator, is_selected) - 元素选中状态符合预期

元素数量
  • presence_of_all_elements_located(locator) - 至少找到一个元素

  • number_of_elements_to_be(locator, number) - 找到特定数量的元素

  • number_of_elements_to_be_less_than(locator, number) - 元素数量少于指定值

  • number_of_elements_to_be_more_than(locator, number) - 元素数量多于指定值

3. 自定义等待条件

如果预定义条件不满足需求,你可以创建自定义等待条件:

from selenium.webdriver.support.ui import WebDriverWait# 自定义等待函数 - 等待元素包含特定类名
def element_has_class(locator, class_name):def predicate(driver):element = driver.find_element(*locator)if class_name in element.get_attribute("class").split():return elementreturn Falsereturn predicate# 使用自定义等待条件
wait = WebDriverWait(driver, 10)
element = wait.until(element_has_class((By.ID, "my-element"), "active"))

4. 高级用法:设置轮询频率和忽略异常

from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import NoSuchElementException# 设置等待时间10秒,每0.5秒检查一次,忽略NoSuchElementException异常
wait = WebDriverWait(driver, timeout=10, poll_frequency=0.5,ignored_exceptions=[NoSuchElementException]
)element = wait.until(EC.visibility_of_element_located((By.ID, "my-element")))

五、混合使用等待策略

最佳实践是结合使用隐式等待和显式等待:

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 Bydriver = webdriver.Chrome()
# 设置一个较短的隐式等待作为后备
driver.implicitly_wait(5)driver.get("https://example.com")try:# 使用显式等待处理关键元素wait = WebDriverWait(driver, 10)login_button = wait.until(EC.element_to_be_clickable((By.ID, "login-btn")))login_button.click()# 等待页面跳转完成(URL变化)wait.until(EC.url_contains("dashboard"))# 等待欢迎消息出现welcome_message = wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "welcome-msg")))print("登录成功:" + welcome_message.text)finally:driver.quit()

六、实战示例:处理动态加载内容

假设有一个页面,点击按钮后通过AJAX加载内容:

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
from selenium.webdriver.common.keys import Keysdriver = webdriver.Chrome()
wait = WebDriverWait(driver, 10)driver.get("https://example.com/dynamic-content")# 点击加载更多按钮
load_more_btn = wait.until(EC.element_to_be_clickable((By.ID, "load-more")))
load_more_btn.click()# 等待新内容加载完成(等待特定元素出现)
# 方法1:等待新增的元素
new_item = wait.until(EC.presence_of_element_located((By.XPATH, "//div[@class='item'][last()]"))
)# 方法2:等待加载指示器消失
wait.until(EC.invisibility_of_element_located((By.ID, "loading-spinner"))
)# 方法3:等待特定数量的元素
wait.until(EC.number_of_elements_to_be((By.CLASS_NAME, "item"), 10)
)print("新内容加载完成!")
driver.quit()

七、常见问题与解决方案

1. 等待超时怎么办?

from selenium.common.exceptions import TimeoutExceptiontry:element = wait.until(EC.visibility_of_element_located((By.ID, "slow-element")))
except TimeoutException:print("元素加载超时,执行备用方案")# 执行其他操作或重新加载页面driver.refresh()# 再次尝试等待element = wait.until(EC.visibility_of_element_located((By.ID, "slow-element")))

2. 处理StaleElementReferenceException

当元素不再附加到DOM时会发生此异常,常见于页面刷新或AJAX更新后:

from selenium.common.exceptions import StaleElementReferenceExceptiondef wait_for_non_stale_element(locator, timeout=10):wait = WebDriverWait(driver, timeout)return wait.until(lambda d: d.find_element(*locator))element = wait_for_non_stale_element((By.ID, "dynamic-element"))

3. 等待多个条件

# 使用lambda表达式组合多个条件
wait.until(lambda d: d.find_element(By.ID, "element1").is_displayed() and d.find_element(By.ID, "element2").is_enabled()
)

八、最佳实践总结

  1. 优先使用显式等待:针对特定条件等待,更加精确和高效

  2. 合理设置超时时间:根据网络速度和页面复杂度设置

  3. 使用合适的预期条件:根据具体需求选择最匹配的条件

  4. 避免混合使用隐式和显式等待:可能导致不可预测的等待时间

  5. 处理异常:使用try-except块处理可能的超时异常

  6. 编写自定义等待条件:当内置条件不满足需求时

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/95244.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/95244.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/95244.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蓓韵安禧活性叶酸独立包装防漏贴心设计

蓓韵安禧叶酸新升级 近期,蓓韵安禧在叶酸产品上进行了重要的优化升级。这次升级的核心在于产品形态和使用体验的显著提升,尤其体现在其包装设计上。新版本采用了独立密封的小包装形式,每一份都精准包含每日所需的叶酸量。这种设计不仅有效避免…

8针脚的1.8寸IIC接口的TFT彩屏的八个引脚都需要使用吗?

核心结论 不需要全部使用8个引脚。实际仅需连接 4根核心线(GND, VCC, SCL, SDA) 即可基本工作,其余引脚为功能增强或备用设计。具体需根据屏幕型号确认,但通用规则如下:8针脚功能分解引脚标号典型名称是否必需作用不连…

刷题日记0831

今日计划5道早上起来不困,吃好早饭开始困了,感觉刷不动题,就先做别的事,不困。现在别的事做好了,感觉能刷动题了。开始开始。7/5134. 加油站 中等超时了。看下题解。不是,怎么上数学了?假设从 x…

【2025.8.31】自学Java三个月,谈谈心路历程顺便给自己灌点鸡汤

自学Java三个月,谈谈心得顺便给自己灌点鸡汤 6月1开始上班,到今天刚好三个月。从上班第一天决定开始自学java,到今天也是正好3个月整,想借这个机会简单记录一下学习java的契机和进度,α一些碎碎念。(括号恐…

linux内核trace_begin和trace_end使用分析

1,strace/ftrace的实现和使用 echo 1 > /sys/kernel/debug/tracing/tracing_on echo function > /sys/kernel/debug/tracing/current_tracer 2, 手动插入追踪点 在内核代码中,可以使用trace_printk函数手动插入追踪点,标记代码段的开始和结束: trace_printk(&…

Linux-驱动积累

Linux 设备驱动概述​Linux 设备驱动是内核与硬件交互的核心桥梁,负责屏蔽硬件细节、提供统一操作接口。其以内核模块为主要存在形式,支持动态加载 / 卸载,核心功能涵盖硬件初始化、中断处理、电源管理及数据传输,是嵌入式 Linux …

软考-系统架构设计师 决策支持系统(DSS)详细讲解

个人博客:blogs.wurp.top 一、DSS的核心概念与定位 1. 什么是DSS? DSS是一个交互式的、计算机化的系统,旨在帮助决策者利用数据和模型来解决半结构化(Semi-structured) 或非结构化(Non-structured&#…

《Python 实战:构建一个可扩展的订单管理系统,从基础操作到架构思维》

《Python 实战:构建一个可扩展的订单管理系统,从基础操作到架构思维》 一、引言:用代码管理商业的脉搏 在数字化浪潮席卷各行各业的今天,订单管理系统已成为电商、物流、零售等领域的核心支撑。它不仅承载着交易数据,更是企业运营效率的体现。而 Python,以其简洁优雅的…

【计算机网络】生产问题排查:如何使用Wireshark抓包/读取抓包文件进行网络分析

1 缘起 有一次,公司同事A让同事B看一次请求日志, 同事B说先抓一次包看看请求是否进入服务器-某个服务, 我知道这个事情后,也“参观”了抓包过程, 上面的事件只是一个小插曲,紧接着的第二件事才是写本篇文章的真正动机: 同一天,同事C让同事D配置个服务代理(某种上网方…

网格dp|

lc3665class Solution {public:int uniquePaths(vector<vector<int>>& grid) {const int MOD 1000000007;int m grid.size(), n grid[0].size();vector memo(m, vector(n, array<int, 2>{-1, -1})); // -1 表示没有计算过auto dfs [&](this auto…

烦人的Nano 编辑器,如何退出呢?

对于不熟悉 nano 编辑器的人来说&#xff0c;它的退出方式确实有点反直觉。别担心&#xff0c;这是几乎所有新手都会遇到的困惑。 退出 Nano 编辑器的正确方法 记住这个黄金法则&#xff1a;ctrl键是你的朋友&#xff01; 1. 正常保存并退出&#xff08;最常用&#xff09; 按 …

IDM(Internet Download Managerv 6.38)破除解版下载!IDM 下载器永久免费版!提升下载速度达5倍!安装及使用

软件介绍 IDM&#xff08;Internet Download Manager&#xff09;是一款功能强大的 Windows 平台专业下载加速工具&#xff0c;可加速下载速度、调度任务、续传下载、管理文件。可使下载速度提升至普通浏览器的 5 倍以上&#xff0c;最高可加速 8 倍。IDM 支持 HTTP、FTP、HTTP…

学习Java29天(tcp多发多收)但是无解决客户端启动多个问题

180/189今天看了一些ip的东西WLAN的ip是路由器随机分配的&#xff08;DHCP&#xff09;

Photoshop - Ps Camera Raw 滤镜

使用Adobe Photoshop Camera Raw滤镜对图像进行快速和可逆的编辑。Camera Raw滤镜将图像拖入Photoshop工作区&#xff0c;或者点击菜单栏-文件-打开来打开图像。选中图像的对应的图层&#xff0c;点击菜单栏-滤镜-Camera Raw滤镜&#xff0c;弹出Camera Raw滤镜面板。使用Camer…

Node.js(4)—— http模块基础

下面我们来学nodejs中的http模块。在此之前&#xff0c;你需要有一定的网络知识储备&#xff0c;能知道http&#xff0c;IP&#xff0c;端口是什么并且它们之间的关系。如果还不清楚或比较模糊&#xff0c;可以查看下面的文章&#xff1a; HTTP协议与IP 下面我们开始学习。 目…

后端去拿数据怎么拿?

简单来说&#xff0c;Entity 和 DTO 代表了数据在不同层次和场景下的不同形态和目的。它们最根本的区别在于&#xff1a;职责和目的不同。一句话概括Entity&#xff1a;代表数据库中的表&#xff0c;是业务逻辑的核心&#xff0c;与持久化&#xff08;数据库&#xff09;紧密相…

从源码角度来学习Activit的启动流程

免责声明&#xff1a;本文是本人的学习记录文档&#xff0c;有问题可以评论区指出&#xff0c;谢谢 一、从Launcher点击桌面图标&#xff0c;拉起app进程&#xff08;不同进程间拉组件&#xff09; 从桌面点击icon图标拉起进程&#xff0c;这个就涉及到很多逻辑了&#xff0c;我…

pgAdmin介绍(PostgreSQL数据库管理软件)数据库客户端、PG客户端、PostgreSQL客户端

文章目录**1. 安装 pgAdmin****1.1 下载****1.2 安装步骤&#xff08;以 Windows 为例&#xff09;**1. **运行安装程序**&#xff1a;双击下载的 .exe 文件。2. **接受协议**&#xff1a;点击 Next&#xff0c;勾选 I accept the agreement。3. **选择安装路径**&#xff1a;默…

桌面GIS软件FlatGeobuf转Shapefile代码分享

桌面GIS软件FlatGeobuf转Shapefile代码分享1、后端代码分享2、前端代码分享分享完成

【Bluedroid】A2DP Source 音频传输停止流程及资源管理机制(btif_a2dp_source_stop_audio_req)

本文深入剖析Android蓝牙协议栈中A2DP音频传输停止流程,涵盖从用户请求触发、工作线程调度、资源释放到性能统计的全链路实现。通过分析btif_a2dp_source_stop_audio_req到btif_a2dp_source_audio_tx_stop_event的代码执行路径,揭示多线程环境下的竞争规避策略、硬件抽象层(H…