浏览器操作综合演示

演示浏览器的各种操作

使用说明

本页面是 Selenium 常用浏览器操作的交互式演示区,共 9 个区域:
① 参数配置:Chrome / Edge / Firefox 选项面板,支持无头模式、User-Agent、下载目录等配置,实时生成 Python 代码
② 打开关闭:get 跳转 URL、close 关闭当前标签、quit 退出整个浏览器,演示页面完整生命周期
③ 页面导航:back 返回上一页、forward 前进到下一页、refresh 刷新当前页面
④ 窗口控制:maximize_window 最大化、minimize_window 最小化、set_window_size/set_window_position/set_window_rect 控制尺寸与坐标
⑤ 页面信息:读取 title 标题、current_url 当前地址、page_source 页面源码、get_log 浏览器日志
⑥ 元素交互:click 点击、send_keys 输入、clear 清空,以及 get_attribute / is_displayed / is_enabled 等属性与状态查询
⑦ Cookie操作:add_cookie 添加、get_cookies / get_cookie 读取、delete_cookie / delete_all_cookies 删除
⑧ 截图保存:save_screenshot 保存到文件、get_screenshot_as_file / get_screenshot_as_base64 / get_screenshot_as_png 多种截图方式,以及元素级别截图
⑨ 超时等待:三种超时(page_load / script / implicit_wait)与 readyState 三阶段详解、Selenium 4 新写法,三种等待方式(强制 sleep / 隐式 implicitly_wait / 显式 WebDriverWait + expected_conditions)对比与最佳实践、超时后处理策略与重试模板
每个区域提供对应的 API 说明、可点击的模拟操作按钮,以及一键复制的 Python Selenium 代码。

参数配置 打开关闭 页面导航 窗口控制 页面信息 元素交互 Cookie操作 截图保存 超时等待
参数配置

参数配置

ChromeOptions / 无头模式 / User-Agent / 下载目录
为什么要配置浏览器?
Selenium 默认启动的是"裸"浏览器,而真实测试往往需要定制:
无头模式 模拟手机 UA 固定下载路径 禁用图片加速 扩展插件
Google Chrome Chromium 内核
全球市场份额 ~65%,Selenium 的"默认参考实现"。
Options 类:add_argument() + add_experimental_option()
驱动:chromedriver.exe(版本号需与浏览器前 3 位匹配)
Microsoft Edge Chromium 内核
Win10/11 预装浏览器,与 Chrome 同内核,API 几乎一致。
独有能力:use_webview=True 测试桌面嵌入应用
隐身参数:--inprivate(Chrome 是 --incognito)
驱动:msedgedriver.exe
Mozilla Firefox Gecko 内核
独立 Gecko 引擎,完全不同的配置体系,反爬首选。
独有方法:set_preference() 直接改 about:config
不支持:excludeSwitches / prefs dict / 隐身模式
驱动:geckodriver.exe
内核差异提示: Chrome/Edge 都是 Chromium 内核,Options API 几乎完全相同(add_argument + add_experimental_option); Firefox 是独立的 Gecko 内核,拥有独有的 set_preference() 方法可精细控制 about:config 全部设置,但不支持 Chromium 专属的 prefs/excludeSwitches/隐身模式。 本界面已根据当前选择的浏览器自动过滤可用配置项并生成对应代码。
配置项(点击切换)
无头模式 默认关
不显示浏览器界面,后台静默运行(CI/服务器必备)
启动即最大化 默认开
--start-maximized,替代 driver.maximize_window()
模拟手机 UA 默认关
伪装成 iPhone 14 Pro,触发移动端页面布局
禁用图片加载 默认关
跳过所有 img 资源,页面加载快 30-50%
隐身模式(隔离会话) 默认关
不继承本机 cookie / 登录态,每次都是全新环境
强制中文 默认关
Accept-Language: zh-CN,zh — 让网站返回中文界面
禁用自动化提示 默认开
excludeSwitches + --disable-infobars
自动下载到指定目录 默认关
prefs.default_directory + 跳过下载弹窗
禁用"保存密码"弹窗 默认关
password_manager_enabled=False
设置 HTTP/HTTPS 代理 默认关
--proxy-server=http://127.0.0.1:7890(Clash/V2Ray)
Service 指定 chromedriver Selenium 4+
Service(executable_path, port=9515) — 独立管理驱动
🔵 Edge 专属
WebView2 模式 Edge 独有
options.use_webview = True — 测试嵌入 WebView2 的桌面应用
实时生成 Python 代码
# 默认 ChromeOptions(无任何配置)
						from selenium.webdriver.chrome.options import Options
						from selenium import webdriver

						options = Options()
						driver = webdriver.Chrome(options=options)
					
点击左侧开关,自动拼出对应的 add_argument() / add_experimental_option() 代码
页面访问

打开关闭

get / close / quit / 页面生命周期
页面的打开与关闭
浏览器自动化的第一步就是"打开目标页面",最后一步是"关闭浏览器"。Selenium 提供了 get、close、quit 三个 API 覆盖完整生命周期。
核心区别: get() 打开页面(导航) close() 关当前页签 quit() 退整个浏览器
⚠️ 常见坑: close() 不关浏览器进程,多标签场景下别用它收尾 | quit() 测试结束务必调用,否则残留进程会吃内存
对应 API:
driver.get("https://xxx") 打开指定网址(https://autotest-505.pages.dev/,点击网址在同一浏览器窗口打开新标签页)
driver.close() 关闭当前页签
driver.quit() 退出整个浏览器(所有页签)
新标签页
about:blank
AutoTest - 首页
Home Setup Locator Action

欢迎来到自动化测试练习平台

这是一个模拟的首页内容,用于演示 driver.get() 打开页面的效果。实际项目中这里会显示完整的首页。

🎯 元素定位
9 种定位方式从入门到精通
🖱️ 元素操作
点击/输入/等待/拖拽全场景
🧪 测试框架
unittest / pytest 实战演练
当前页签已被 driver.close() 关闭
Python Selenium · 打开与关闭浏览器完整示例
# ① 启动 Chrome 浏览器
from selenium import webdriver
from selenium.webdriver.common.by import By
import psutil, time   # 进程对比用,需先 pip install psutil

# 采集 chrome / chromedriver 进程 PID 集合的辅助函数
def procs():
    return {p.pid for p in psutil.process_iter(["name"])
            if p.info["name"] in ("chrome.exe", "chromedriver.exe")}

_pids = procs()   # 启动前基线,排除你自己开着的 Chrome
driver = webdriver.Chrome()

# ② 打开演示页面(此时只有这一个标签页)
driver.get("https://autotest-505.pages.dev/browser_op_tech_sections/open_close_tech.html")
print("启动后新增进程:", procs() - _pids)   # chromedriver.exe + 若干 chrome.exe

# ③ 点击“对应 API”区域中的 https://autotest-505.pages.dev/ 链接
#    该链接 target="_blank",点击后会在【同一浏览器窗口】里新开一个标签页
#    注意:点击后 driver 的焦点仍停留在原标签页,这里不做标签页切换
driver.find_element(By.CSS_SELECTOR,
                    'a[href="https://autotest-505.pages.dev/"]').click()
time.sleep(1)   # 等新标签页进程稳定
print("点击后新增进程:", procs() - _pids)   # 新标签页触发 Chrome 多进程架构创建渲染进程(也可能复用)

# ④ close():只关闭 driver 当前所在标签页,另一个不受影响;用 3 个信号对比(和 quit 后三行完全镜像)
driver.close()
print("close 后残留进程:", procs() - _pids)                     # 非空集合:chrome/chromedriver 都还活着
print("chromedriver 进程状态:", driver.service.process.poll())  # None:进程仍在运行(未退出)
print("驱动还能连接吗:", driver.service.is_connectable())     # True:会话仍存活

# ⑤ quit():关闭所有剩余标签页并退出浏览器进程(无需先切换标签);用 3 个确定性信号佐证
driver.quit()
time.sleep(1)   # 等系统回收进程
print("quit 后残留进程:", procs() - _pids)                    # set():chrome/chromedriver 全部退出
print("chromedriver 退出码:", driver.service.process.poll())  # 0:驱动进程已正常结束
print("驱动还能连接吗:", driver.service.is_connectable())     # False:driver 已释放
# 注意:Selenium 4 的 quit() 不会把 driver.session_id 置空,不要用它判断会话是否结束
操作效果展示区域
点击上方按钮,这里会显示 Selenium API 执行结果和关键数据
窗口控制

窗口控制

maximize_window / minimize_window / set_window_size / set_window_position / set_window_rect
窗口的大小与位置
Selenium 可以精确控制浏览器窗口在屏幕上的尺寸和坐标,满足不同测试场景需求:从"全屏铺满"到"自定义 800×600 放在屏幕中央",甚至拖到指定位置。
应用场景: 最大化:消除浏览器边框干扰 自定义尺寸:测试不同分辨率 UI 多窗口排列:并行测试对比
⚠️ 常见坑: maximize 和 fullscreen 不一样:前者保留任务栏,后者 F11 沉浸式 | set_window_rect 是 Selenium 4 新增,一次搞定尺寸+位置
对应 API:
driver.maximize_window() 最大化窗口
driver.minimize_window() 最小化窗口
driver.fullscreen_window() 全屏(F11)
driver.set_window_size(w, h) 设置尺寸
driver.set_window_position(x, y) 设置位置
driver.set_window_rect(x, y, width, height) 同时设置尺寸和位置
driver.get_window_size() 获取尺寸,返回 {'width':w, 'height':h}
driver.get_window_position() 获取左上角坐标
窗口宽度
-
窗口高度
-
(浏览器内部视口大小,练习 Selenium 中 window_size API)
按 ESC 或点击退出全屏
新标签页
chrome://newtab

欢迎来到 AutoTest

Selenium 自动化测试练习平台

⊞
AutoTest Chrome
--:--
1024 × 768
自定义窗口尺寸 / 位置
Python Selenium · 窗口控制完整示例
# ① 启动浏览器并打开窗口控制演示页
from selenium import webdriver

driver = webdriver.Chrome()
driver.get("https://autotest-505.pages.dev/browser_op_tech_sections/window_control_tech.html")

# ② 设置 / 获取窗口尺寸(单位:像素)
driver.set_window_size(1024, 768)
print(driver.get_window_size())        # {'width': 1024, 'height': 768}

# ③ 设置 / 获取窗口位置(相对屏幕左上角)
driver.set_window_position(100, 50)
print(driver.get_window_position())    # {'x': 100, 'y': 50}

# ④ 一次设置 x / y / width / height
driver.set_window_rect(x=0, y=0, width=1280, height=800)

# ⑤ 最大化 / 最小化 / 全屏(等同 F11)
driver.maximize_window()
driver.minimize_window()
driver.fullscreen_window()

# ⑥ 结束会话
driver.quit()
操作效果展示区域
点击上方按钮,这里会显示 Selenium API 执行结果和关键数据
页面信息

页面信息

title / current_url / page_source / get_log
为什么要获取页面信息?
自动化测试中,"先拿到当前页面的信息再做判断"是常见套路——比如标题对不对、URL 是不是跳转到了预期地址、页面源码里有没有某个关键字。
常见用途: 断言跳转是否成功 验证页面标题 抓取 HTML 做解析 Console 日志采集
⚠️ 常见坑: page_source 返回完整 HTML,可能非常大,谨慎打印 | current_url 包含 hash(#后面的部分),断言时注意
对应 API:
driver.title 获取当前页面标题
driver.current_url 获取当前页面完整 URL
driver.page_source 获取当前页面完整 HTML 源码
driver.name 获取当前浏览器名称(如 chrome / firefox)
driver.get_log("browser") 获取浏览器 Console 日志
页面标题 (title)
— 未获取 —
当前地址 (current_url)
— 未获取 —
源码长度 (page_source)
— 未获取 —
浏览器名称 (name)
— 未获取 —
Python Selenium · 获取页面信息完整示例
# ① 启动浏览器
from selenium import webdriver

driver = webdriver.Chrome()
driver.get("https://autotest-505.pages.dev/browser_op_tech_sections/page_info_tech.html")

# ② 获取页面标题(<title> 标签内容)
print("标题:", driver.title)

# ③ 获取当前完整 URL(常用于验证页面跳转是否成功)
print("URL:", driver.current_url)

# ④ 获取页面 HTML 源码
print("源码长度:", len(driver.page_source))

# ⑤ 浏览器名称、当前窗口句柄与全部句柄
print("浏览器:", driver.name)
print("当前句柄:", driver.current_window_handle)
print("所有句柄:", driver.window_handles)

driver.quit()
操作效果展示区域
点击上方按钮,这里会显示 Selenium API 执行结果和关键数据
元素交互

元素交互

click / send_keys / clear / get_attribute / is_displayed / is_enabled
为什么要学习元素交互?
定位到元素后,真正干活的就是这几个交互方法——输入、点击、清空、读属性。它们是自动化脚本的"手脚"。
常见用途: 登录注册(输入账号密码) 点击按钮/链接 表单填写提交 获取元素属性做断言
⚠️ 常见坑: ElementNotInteractableException 元素存在但不可交互(被遮挡/没滚动到) | click() 点不到时试试 driver.execute_script("arguments[0].click()", el) 用 JS 强制点击(el 就是你用 find_element() 定位到的那个元素对象,execute_script 会把它作为参数传给 JS 里的 arguments[0],相当于绕过 Selenium 的可交互性检查直接触发 DOM 事件)
对应 API:
element.click() 点击元素
element.send_keys("text") 输入文本(配合 Keys.ENTER 可模拟回车)
element.clear() 清空输入框
element.submit() 表单提交(等同于在输入框按回车)
element.text 获取元素可见文本
element.get_attribute("href") 获取 HTML 属性
element.get_property("value") 获取 DOM property(比 get_attribute 更可靠,比如读输入框当前值)
element.tag_name 获取标签名(如 "input" / "button")
element.size 获取尺寸 {'height': N, 'width': N}
element.location 获取页面坐标 {'x': N, 'y': N}
element.rect 获取完整的位置+尺寸对象
element.is_displayed() 元素是否可见
element.is_enabled() 元素是否可操作
element.is_selected() 复选框/单选框是否选中
模拟操作目标(点击下方按钮操作这些元素)
代码开关(开=右侧显示对应代码)
send_keys("admin")
输入用户名
send_keys("123456")
输入密码
clear()
清空用户名输入框
clear()
清空密码输入框
click()
点击按钮
submit()
回车提交
.text
获取文本
get_attribute()
HTML 属性
get_property()
DOM 属性
tag_name
标签名
size
元素尺寸
location
页面坐标
rect
完整矩形
is_selected()
是否选中
is_displayed()
是否可见
is_enabled()
是否可点
对应 Python Selenium 代码
点击下方开关,这里将生成对应的 Selenium 代码...
Python Selenium · 元素交互完整示例
# ① 启动浏览器并打开元素交互演示页
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://autotest-505.pages.dev/browser_op_tech_sections/element_interact_tech.html")

# ② 定位输入框与复选框(id 与本演示页真实元素一致)
username = driver.find_element(By.ID, "mockUsername")
password = driver.find_element(By.ID, "mockPassword")
remember = driver.find_element(By.ID, "mockRemember")

# ③ 输入文本、清空后重新输入
username.send_keys("admin")
username.clear()
username.send_keys("admin")
password.send_keys("123456")

# ④ 点击复选框;submit() 模拟回车提交表单
remember.click()
password.submit()

# ⑤ 读取元素属性与状态(自动化断言常用)
print("placeholder:", username.get_attribute("placeholder"))
print("标签名:", username.tag_name)
print("尺寸/坐标/矩形:", username.size, username.location, username.rect)
print("选中/可见/可用:", remember.is_selected(), username.is_displayed(), username.is_enabled())

driver.quit()
操作效果展示区域
点击模拟登录按钮或切换开关,这里会显示元素操作的执行结果和关键数据
截图操作

截图保存

save_screenshot / get_screenshot_as_file / 元素截图
为什么需要截图?
自动化测试中,截图是"留证据"的关键手段。测试执行完毕后(尤其是失败时),一张截图可以让你直观地看到当时页面长什么样,是调试和报告的核心素材。
常见用途: 测试失败自动截图 视觉回归对比 登录验证留档
5 种截图 API 对比
API 截图范围 返回值 写到文件? 适用场景
driver.save_screenshot("a.png")视口True/False✅ 是最常用,直接存本地
driver.get_screenshot_as_file("a.png")视口True/False✅ 是同 save_screenshot,API 更冗长(遗留)
driver.get_screenshot_as_base64()视口base64 str❌ 否嵌入 Allure/pytest-html 报告
driver.get_screenshot_as_png()视口bytes 二进制❌ 否内存处理,上传 OCR/AI
element.screenshot("a.png")元素True/False✅ 是只截某个元素(Selenium 4+)
选型速查: 存本地 → save_screenshot | 嵌入 HTML → get_screenshot_as_base64 | 上传 AI → get_screenshot_as_png | 只截按钮/验证码 → element.screenshot
⚠️ 重要认知:所有 driver 级截图都是视口截图(viewport),只截取当前视口的浏览器内容可见区域,不会自动滚动去截上下方的内容!
要实现"全页截图"需额外手段:headless Chrome + --full-page-screenshot、selenium-screenshot 库、或 JS 滚动拼接。
截图演示区
新标签页
https://demo.autotest.com/index.html
🏠 自动化测试首页
欢迎来到练习平台
📦 功能模块 A
视口可见
📦 功能模块 B
需滚动才看到
📦 功能模块 C
需滚动才看到
📦 功能模块 D
需滚动才看到
📦 功能模块 E
需滚动才看到
⊞
AutoTest Chrome
280 × 190
5 种截图 API · 点击演示
前 4 种 driver 级 API 截图区域完全相同(浏览器 视口,不含标题栏/地址栏),区别只在返回值类型和是否写文件。
第 5 种 element.screenshot 只截指定元素(按钮/验证码等),Selenium 4+ 支持。
save_screenshot
视口保存到文件(最常用)
get_screenshot_as_file
视口写文件(遗留 API)
get_screenshot_as_base64
视口截图 → base64 字符串
get_screenshot_as_png
视口截图 → PNG bytes
element.screenshot
只截某个元素(Selenium 4+)
点击上方 5 种 API 卡片,这里会生成真实的 Canvas 截图缩略图
Python Selenium · 截图保存完整示例
# ① 启动浏览器并打开截图演示页
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://autotest-505.pages.dev/browser_op_tech_sections/screenshot_tech.html")

# ② 整页(视口)截图保存为文件,成功返回 True
print(driver.save_screenshot("full.png"))
driver.get_screenshot_as_file("full2.png")          # 等价写法

# ③ 截图为 base64 字符串,适合直接嵌入 HTML 测试报告
b64 = driver.get_screenshot_as_base64()

# ④ 截图为 PNG 二进制 bytes,可在内存中处理或上传到服务器
png_data = driver.get_screenshot_as_png()
with open("from_bytes.png", "wb") as f:
    f.write(png_data)

# ⑤ 只截取单个元素(Selenium 4+,id 与本演示页按钮一致)
btn = driver.find_element(By.ID, "shotBtnElement")
btn.screenshot("element.png")

driver.quit()
操作效果展示区域
点击上方按钮,这里会显示 Selenium API 执行结果和关键数据
超时与等待

超时控制与等待机制

page_load_timeout / script_timeout / implicitly_wait / WebDriverWait / time.sleep

超时控制(Timeouts)

page_load_timeout / script_timeout / implicitly_wait
什么是超时?—— "上限策略,防卡死"
Selenium 脚本执行速度快,但网页加载慢、网络不稳定、服务器偶发宕机。如果不设超时,默认等 300 秒(5 分钟)才会放弃——一个死链就会把整个测试套件拖死。
超时的本质: 设上限,过了就放弃 防脚本被卡死拖死 正常页面不受影响
⚠️ 核心认知:超时设 30s,页面 5s 正常加载完 → 还是 5s 返回。超时只影响"超过时间还没完成"的异常情况,对正常页面没有任何性能损失。
Selenium 三种超时完整对比
超时类型 方法调用 API(Selenium 3/4 通用) 属性赋值 API(Selenium 4+ 推荐) 等什么 谁触发 初始值
页面加载超时driver.set_page_load_timeout(30)driver.timeouts.page_load = 30等 readyState = "complete" get / back / forward / refresh 300s
脚本执行超时driver.set_script_timeout(10)driver.timeouts.script = 10等 JS 脚本执行完毕 execute_script / execute_async_script 30s
隐式等待超时driver.implicitly_wait(3)driver.timeouts.implicit_wait = 3等元素出现在 DOM 中 find_element / find_elements 0s(关闭)
Selenium 4 统一写法(推荐):
from selenium.webdriver.common.timeouts import Timeouts
driver.timeouts = Timeouts(implicit_wait=3, page_load=30, script=10)
✅ 既能赋值,也能读值(旧写法做不到): print(driver.timeouts.page_load) → 返回当前 page_load 值
怎么设合理的超时值?
方法:找一台能稳定访问的电脑,刷新目标页面 10 次,取其中第 9 快的那个时间(P90),再加 5~10 秒缓冲。
网站类型 page_load_timeout 建议值 script_timeout 建议值 隐式等待建议值
公开官网 / 博客 / API 文档10 ~ 15 秒5 秒1 ~ 2 秒
一般业务系统(OA、CRM)20 ~ 30 秒10 秒2 ~ 3 秒
中后台管理系统(有图表)45 ~ 60 秒15 秒2 ~ 3 秒
内部系统(VPN/内网)60 ~ 90 秒20 秒3 秒
大数据看板 / BI 报表90 ~ 120 秒30 秒3 秒
⚠️ 超过 120 秒还加载不完的页面,不是该调大超时,是该优化系统(前端代码、后端接口、数据库查询)。
超时后怎么办?—— window.stop() + 重试 / 跳过 / 截图留证
⚠️ 超时时绝不要在"半加载的坏页面"上继续定位元素,大概率找不到或找错。正确做法是:
① window.stop()
把浏览器从"半卡半死的 loading"拉回来,让后续 get() 能正常执行。
driver.execute_script("window.stop()")
② 截图留证
自动化测试中超时务必截图,Allure/pytest-html 会自动附到报告上。
driver.save_screenshot("timeout.png")
③ 重试 / 跳过
重试几次还不行就放弃,不要让一个失败拖住整个脚本。
# 生产级 safe_get 重试模板
from selenium.common.exceptions import TimeoutException

def safe_get(driver, url, retries=3):
    for attempt in range(1, retries + 1):
        try:
            driver.get(url)
            return True # ✅ 成功
        except TimeoutException:
            driver.execute_script("window.stop()") # 救回浏览器
            driver.delete_all_cookies()
            driver.save_screenshot(f"timeout_attempt{attempt}.png")
    return False # ❌ 彻底放弃
设置超时的影响
about:blank
📋 Dashboard
Loading...
Loading...
Loading...
加载中...
加载中...
#
Name
Status
1
Task Alpha
...
2
Task Beta
...
readyState: — ⏱ 0.00s
演示统计
选择下方按钮开始演示
观察超时机制的效果差异
「超时」设置
s
s
s
page_load
script
implicit
全部应用
当前演示区配置:未设置
选择超时场景模拟效果
演示重点: page_load_timeout 管页面加载, script_timeout 管 execute_script, implicitly_wait 管 find_element。
💡 超时设置建议
✅ page_load_timeout 建议设 30s —— WebDriver session 创建后初始值为 300s(5 分钟,W3C 规范规定)
    └ 一个页面资源卡住就白等 5 分钟,整个测试套件被拖慢数倍
❌ 不调用 set_page_load_timeout() 就会一直用页面加载超时初始值 300s(太长,正常页面加载用不了这么久)
✅ WebDriver session 创建后统一设一次超时,后面所有 get() 自动生效
❌ 避免每个 get() 前都重新 set_page_load_timeout —— 既冗余又容易漏改
✅ TimeoutException 异常完整处置流程:捕获 → driver.execute_script("window.stop()") → 重试/跳过/截图留证
❌ 只 catch 不 stop(浏览器仍 loading,后续操作不可控);或想让测试 fail-fast 时瞎 catch(超时不暴露问题)
超时演示页面
🔐 示例网站登录
📖 演示说明
在左侧表单输入用户名和密码,点击「登录」即可看到结果。模拟三层超时代码中 driver.find_element("id", ...) 的定位流程。
⏱ 三层超时分别控制哪行代码?
page_load=30s → driver.get(".../login") ← 页面导航最长等 30s
script=10s → driver.execute_script("...") ← 同步 JS 执行最长等 10s
implicit_wait=1s → find_element("id", "username") ← 找不到元素时重试最多 1s
implicit_wait=1s → find_element("id", "password") ← 同上
implicit_wait=1s → find_element("id", "login-btn") ← 同上
implicit_wait=1s → find_element("id", "page-title") ← 同上
💡 核心教学点
这是 三层超时配置 的配套 demo——没有显式等待(WebDriverWait),
全靠 page_load=30s + script=10s + implicit_wait=1s 三层超时兜底。
适合页面结构简单、不需要精确等待的场景。
最佳实践:三层超时配置(生产代码推荐写法)
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.timeouts import Timeouts
from selenium.common.exceptions import TimeoutException

# ═══════════════════════════════════════
# 初始化:Selenium 4 三层超时统一配置
# ═══════════════════════════════════════
options = Options()
options.add_argument("--headless=new")
driver = webdriver.Chrome(options=options)

# ─── 方案一:Selenium 4 新写法(推荐,Pythonic) ───
driver.timeouts = Timeouts(
    page_load=30, # 第 1 层:页面导航上限 30s(必设)
    script=10, # 第 2 层:JS 执行上限 10s(必设)
    implicit_wait=1 # 第 3 层:元素查找兜底 1s(极短兜底)
)

# ─── 方案二:传统 API 写法(效果相同,逐行设置) ───
# driver.set_page_load_timeout(30) # 第 1 层
# driver.set_script_timeout(10) # 第 2 层
# driver.implicitly_wait(1) # 第 3 层

# ═══════════════════════════════════════
# 执行:基本业务流程
# ═══════════════════════════════════════
try:
    driver.get("https://example.com/login")

    driver.execute_script("document.title = '登录中...'") # 受控于 script=10s

    driver.find_element("id", "username").send_keys("admin")
    driver.find_element("id", "password").send_keys("secret")
    driver.find_element("id", "login-btn").click()

    title = driver.find_element("id", "page-title").text
    print(f"✅ 登录成功:{title}")
except TimeoutException as e:
    driver.execute_script("window.stop()")
    driver.save_screenshot("fail.png")
    print(f"❌ 超时:{e}")
finally:
    driver.quit()

等待机制(Waits)

time.sleep / implicitly_wait / WebDriverWait + expected_conditions
什么是等待?—— "积极轮询,等条件变好"
和超时的被动"设上限、过了就放弃"完全不同,等待是主动的"我愿意花时间等条件满足"。Selenium 能做的唯一方式是 轮询(浏览器无法主动推事件给 Python)。
三个概念一句话总结: sleep = 硬等,不管页面 implicitly_wait = 全局兜底 WebDriverWait = 精准打击(推荐)
⚠️ 轮询的本质:WebDriver 协议是 HTTP/JSON-Wire 协议,浏览器不能主动推事件给 Python,所以 Selenium 只能:每隔 N 毫秒问一次"条件满足了吗?" → 满足就返回,超时就报错。
Selenium 三种等待完整对比
分类 API 作用范围 轮询频率 等什么 评级
⏱ 硬等time.sleep(N)当前这一行无啥都不等,暂停线程 N 秒🔴 避免
🛡 隐式等待implicitly_wait(N)全局所有 find_element驱动内部(不固定)元素出现于 DOM🟡 谨慎
🎯 显式等待WebDriverWait().until()这一次调用可配(默认 500ms)任何条件(20+ 种)🟢 首选
关键认知:超时是"被动设上限,过了就放弃";等待是"主动轮询,等条件变好"。两者是共生关系:没有超时的等待会死等(脚本卡死),没有等待的超时时立即报错。
概念全景图 —— 一图看懂 Selenium 等待机制全貌
等待机制 Waits
硬等
time.sleep(N)
📍当前行 ⏱睡死 🔴无轮询
时间驱动
(不管条件)
隐式等待
implicitly_wait(N)
🌐全局 🔒固定条件 ⚡驱动内部
状态驱动 · 全局
(等元素出现)
显式等待
WebDriverWait
until()
条件成真
EC
预定义
lambda
自定义
until_not()
条件成假
EC
预定义
lambda
自定义
状态驱动 · 局部
(等条件变好)
time.sleep → 时间驱动
implicitly_wait → 状态 · 全局
WebDriverWait → 状态 · 局部
三大致命坑点 —— 90% 的自动化脚本至少踩过一个
坑 1:implicitly_wait 设太大(≥5s)
全局污染!所有 find_element 都被迫轮询 5 秒,连 "确认元素不存在" 这种本来瞬间返回的场景,也要傻等满 5 秒才抛 NoSuchElementException。
driver.implicitly_wait(10) # ❌ 设太大
try:
driver.find_element(By.ID, "ghost") # 不存在
except NoSuchElementException:
pass # 也要傻等 10 秒 💀
坑 2:隐式等待 + 显式等待叠加灾难
显式等待内部用 find_element,find_element 被隐式等待包了一层。最坏情况:隐式 10s × 显式 10 次轮询 = 几分钟!Selenium 自己都不知道怎么回事。
driver.implicitly_wait(10) # 隐式 10s
wait = WebDriverWait(driver, 15) # 显式 15s
wait.until(EC.presence_of_element_located((By.ID, "never"))) # 最坏 10s × 15 = 150s
坑 3:用 presence 代替 clickable 来点击按钮
presence 只保证 DOM 里有,不保证没被遮罩。点按钮遇到 ElementClickInterceptedException(被 loading 遮罩盖着),就是因为用了 presence / visibility 没检查是否可点击。
模拟等待的影响
about:blank
📋 Dashboard
Loading...
Loading...
Loading...
加载中...
加载中...
#
Name
Status
1
Alice
—
2
Bob
—
状态:空闲 ⏱ 0.00s
演示统计
选择下方按钮开始演示
观察等待机制的效果差异
「等待」设置
s
s
s (poll_frequency: s)
time.sleep
implicitly_wait
WebDriverWait
当前演示区配置:sleep=3s, implicit=5s, explicit=10s
选择等待方式模拟效果
⚠️ 以下模拟 等待超时、元素找不到 的场景:
演示重点: time.sleep 傻等不管页面 → 推荐用 WebDriverWait 精准等条件。
💡 元素等待策略建议
✅ 隐式等待要么全程不设(默认就是 0,最严谨),要么全程 ≤1s做极短兜底
❌ 避免设 ≥5s,更不要中途频繁切换隐式值(容易忘开回去、叠加变长)
✅ 所有关键步骤 用显式等待(WebDriverWait + EC)精准覆盖
❌ 避免用 time.sleep 代替 —— 机器快白等、慢就崩,CI/CD 上尤其不稳定
❌ 例外:等 CSS 动画完成 / 截图前稳定 / 调试时插入 time.sleep() 查看中间状态
✅ 显式等待条件匹配操作意图,条件层级由强到弱:clickable > visibility > presence
✅ 要点击某个按钮(操作意图:点击) → clickable(确保没被遮罩、没 disabled)
✅ 等提示消息出现(操作意图:等可见) → visibility(确保可见)
✅ 只关心 DOM 里有没有(操作意图:检查存在) → presence(确保元素在 DOM 中存在,可以是隐藏的)
❌ 别用弱等级条件代替强等级(例:别用 presence 代替 clickable 等待要点击的按钮 —— 元素可能在 DOM 里但被遮罩盖着或 disabled)
演示页面 —— 代码中的 4 种等待条件都在这里
加载中...
📊 用户控制台
📖 演示说明 (点击「模拟加载」再点击「登录」可观察完整流程)
点击「模拟加载」→ loader 旋转 2.5s 后消失,标题淡入、登录按钮解锁 → 点击「登录」→ URL 跳转 + 绿色 toast 出现。
代码 ↔ 元素 & EC 条件
EC.invisibility → #loader ← 遮罩消失
EC.visibility → #title ← 标题出现
EC.clickable → #login-btn ← 按钮可点
EC.url_contains → dashboard ← URL 跳转
EC.visibility → #toast-success ← 成功提示
💡 核心教学点
代码中 没有 time.sleep(),全靠 wait.until(EC.xxx)。
sleep 是硬等(网络快了浪费、慢了不够用),EC 是条件驱动(满足即往下走,自适应)。
最佳实践:三层等待(生产代码推荐模板)
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.common.exceptions import TimeoutException, NoSuchElementException

# ═══════════════════════════════════════
# 初始化:一层隐式等待兜底(生产代码不用 sleep)
# ═══════════════════════════════════════
driver = webdriver.Chrome()
driver.implicitly_wait(1) # 隐式等待:find_element 兜底 1s(极短兜底)

# 创建显式等待对象(单次精准打击)
wait = WebDriverWait(driver, 15, poll_frequency=0.3, ignored_exceptions=(NoSuchElementException,))

# ═══════════════════════════════════════
# 执行:显式等待链覆盖每个关键步骤
# ═══════════════════════════════════════
try:
    driver.get("https://example.com")

    wait.until(EC.invisibility_of_element_located((By.ID, "loader")))
    wait.until(EC.visibility_of_element_located((By.ID, "title")))

    login = wait.until(EC.element_to_be_clickable((By.ID, "login-btn")))
    login.click()

    wait.until(EC.url_contains("dashboard"))

    success = wait.until(EC.visibility_of_element_located((By.ID, "toast-success")))
    print(f"✅ 登录成功:{success.text}")
except TimeoutException as e:
    driver.save_screenshot("fail.png")
    print(f"❌ 超时:{e}")
finally:
    driver.quit()
Python Selenium · 超时设置与显式等待完整示例
# ① 启动浏览器
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Chrome()

# ② 三类超时设置(单位:秒)
driver.set_page_load_timeout(30)     # 页面导航加载最多等 30s
driver.set_script_timeout(10)        # execute_script 最多等 10s
driver.implicitly_wait(1)            # find_element 兜底轮询最多 1s

driver.get("https://autotest-505.pages.dev/browser_op_tech_sections/timeout_wait_tech.html")

# ③ JS 注入:execute_script 受 set_script_timeout(10) 保护,脚本卡住最多抛超时异常
ready_state = driver.execute_script("return document.readyState")
print("页面加载状态:", ready_state)   # complete

# 注入 JS 直接读取元素文本(不经过 Selenium 定位器)
card_text = driver.execute_script("return document.getElementById('mockCard1').innerText;")
print("卡片内容:", card_text)

# ④ 普通定位:find_element 受 implicitly_wait(1) 保护,元素没立即出现时兜底轮询最多 1s
sleep_btn = driver.find_element(By.ID, "waitBtnSleep")
print("定位到按钮:", sleep_btn.text)

# ⑤ 显式等待(推荐):每 0.5s 轮询一次,最长等 10s
wait = WebDriverWait(driver, 10, poll_frequency=0.5)

# 等按钮可点击后再点击(id 与本演示页“显式等待”按钮一致)
btn = wait.until(EC.element_to_be_clickable((By.ID, "waitBtnExp")))
btn.click()

# 等异步加载的卡片变为可见(id 与本演示页动态元素一致)
wait.until(EC.visibility_of_element_located((By.ID, "mockCard1")))

# ⑥ 结束会话
driver.quit()
操作效果展示区域
点击上方按钮,这里会显示 Selenium 超时 API 的配置结果和关键数据

关于我们

Python 自动化测试学习平台是一个面向软件测试工程师、开发人员及在校学生的交互式在线学习平台,专注于 Selenium WebDriver 与 Python unittest 自动化测试技能的教学与实践。

我们以"理论 + 实战 + 可交互演示"为核心特色,将八种常规元素定位和Javascript定位、元素操作、自动化测试工具、单元测试、测试模型等知识体系拆分为模块化课程,每个模块都配有可点击、可输入、可运行的模拟练习页面。

平台致力于降低自动化测试的入门门槛,让学习者从"看懂代码"到"动手实操",逐步掌握企业级自动化测试框架的设计与落地能力。

联系方式

📧邮箱:lq@selenium-auto-test.com

📞电话:0755-12345678

📍地址:深圳

💬微信公众号:Selenium自动化测试

🐙GitHub:github.com/selenium-auto-test

免责声明

1. 本平台所有示例代码、演示页面及教程内容均仅供学习交流使用,不构成任何商业推广或技术服务承诺。

2. 平台中的 Selenium API 描述、Python 语法说明均以官方文档为准,如有版本差异请以对应官方文档为准。

3. 学习者在实际项目中应用平台所学内容时,应结合自身项目环境进行充分测试,本平台不对因直接使用示例代码而产生的任何直接或间接损失承担责任。

4. 本平台所引用的第三方库(Selenium、ChromeDriver、unittest 等)版权归其各自作者及维护者所有。

5. 如涉及版权问题或内容建议,请及时通过联系方式与我们沟通,我们将第一时间处理。

CI/CD:自动化测试的真实运行环境
CI/CD 是什么?

● CI = Continuous Integration(持续集成)
代码推送到 Git 仓库后,自动拉代码 → 装依赖 → 跑测试,每次 push 都帮你检查有没有问题。

● CD = Continuous Delivery(持续交付)
CI 通过后自动打包 → 发到服务器 → 重启,不用手动部署。
(另一种 Continuous Deployment 是全自动部署到生产,不用人审批)

CI/CD 完整流水线

你写了一行代码 → git push origin main
↓
GitHub(或 GitLab / Jenkins / Gitee)收到推送
↓
自动触发一条 Pipeline(流水线)
① Checkout(拉代码)
把你刚推的代码拉到一台全新的云服务器上
↓
② Install(装依赖)
pip install -r requirements.txt
装 Chrome、装 ChromeDriver
↓
③ Build(构建)
打包成可部署的产物(.tar.gz / Docker 镜像 / ...)
↓
④ Test(跑测试)
pytest unit_tests/  # 单元测试
pytest selenium_tests/ # ⬅️ Selenium 在这里上场!
代码覆盖率检查 · 代码风格检查
↓
全部通过?
╱    ╲
是    否
↓    ↓
⑤ Deploy
自动发到服务器
生产环境立刻更新
❌ 失败
发邮件/钉钉通知你
修复 → 重新 push

Selenium 在 CI/CD 里扮演什么角色?
Selenium 测试脚本是流水线 第 ④ 阶段(Test) 的核心。CI 服务器会:
1. 在全新的云服务器上装 Python + Chrome + ChromeDriver
2. 以 headless(无头)模式启动 Chrome(没有 GUI,更快但渲染行为和本地略有差异)
3. 运行你的 pytest + Selenium 脚本,模拟真实用户操作(登录、搜索、下单...)
4. 全部通过才允许部署到生产;任何一步失败 → 发邮件通知 → 生产不会被污染

核心好处:每次代码合进来都有 Selenium 帮你模拟真实用户过一遍关键路径,而不是等到用户反馈"登录不了了"。

为什么 CI/CD 上 sleep 特别容易崩?
CI 环境每次都是全新的云服务器,和本地有几个关键差异:
因素 本地 CI/CD 云服务器
网络专线稳定数据中心共享,偶发抖动
CPU独占多租户,可能被抢占
浏览器缓存有没有(每次全新启动)
页面加载速度有缓存,秒出全量下载,慢 2~5 倍
并发任务只跑你这一份可能几十上百个同时抢资源

同样的 sleep(3):
本地:按钮 2s 出来 → sleep 3s → 白等 1s 但能过 ✅
CI 上:按钮 6s 出来 → sleep 3s 已经过了 → find_element 找不着 → 💥

这就是为什么说 CI/CD 上尤其不稳定 —— CI 是一台你控制不了但天天要给你打分的云电脑,每次环境都不一样。
而 WebDriverWait 是"等条件满足就行,最多等 10s 上限" —— 对 CI 环境的波动天然免疫。
为什么推荐 ≤1s
📌 隐式等待超时值的语义(W3C 规范定义)
隐式等待的"兜底窗口"即 implicitly_wait(N) 所设置的 N 值本身,此结论直接来自 W3C WebDriver 规范:
"A session has an associated session implicit wait timeout that specifies a time to wait for the implicit element location strategy"
→ 驱动在一次 findElement / findElements 调用中,最多愿意等待的总时间即为该值,不得超时。
implicit=0.5s → 驱动最多等待 500ms 后必须放弃
implicit=1.0s → 驱动最多等待 1000ms 后必须放弃
implicit=0 → 驱动立即执行一次查询,不进行重试(默认值)

以上定义为 W3C 规范层面的硬约束,与驱动实现无关,是选择 implicit 值、计算叠加成本、规划白等上限的直接依据。
🔍 驱动内部轮询机制——规范未作规定
W3C 规范对隐式等待仅定义了超时值的语义(见上文),对驱动内部的轮询实现细节完全未做约束。具体而言,规范未规定: 以 ChromeDriver 为例,可通过让元素延迟插入 DOM、记录 find_element 实际耗时的方法进行观测:在常规负载下元素出现后约 50~70ms 内即可被查到;若同一驱动连续处理多次请求,该值可能飘至 200ms 以上。换驱动版本或换机器,结果也可能不同。
🔧 实测代码(可自行跑一遍验证你的驱动) 原理:让元素在指定延迟后才插入 DOM,调用 find_element 记录实际耗时。耗时减去延迟得到"元素出现后驱动最晚多久查到"。
延迟点密集覆盖 10~1500ms,跑一轮后取差值区间的上界,即为该驱动在当前负载下的轮询间隔量级。
同一驱动连续处理多次查找请求,若差值区间明显漂移,说明驱动的轮询节奏已不稳定。
from selenium import webdriver
from selenium.webdriver.common.by import By
import time

def test_polling(d, delay):
    d.implicitly_wait(2)
    d.get('about:blank')
    d.execute_script(f"setTimeout(()=>{{document.body.innerHTML='
t
'}},{delay})") t0 = time.perf_counter() try: cost = (time.perf_counter() - t0) * 1000 print(f"delay={delay:4d} 耗时={cost:6.0f} 差值={cost-delay:+5.0f}") except: print(f"delay={delay} 超时") driver = webdriver.Chrome() for delay in range(10, 1550, 50): # 50ms 步进,覆盖 10~1500ms test_polling(driver, delay) driver.quit()

⚖️ 那 ≤1s 怎么选出来的?—— 经验 + 权衡
经验观察
竞态(race condition,脚本发起 find_element 的时刻与元素实际出现于 DOM 的时刻之间的竞态)通常差 200~500ms: 注:以上是前端性能的普遍经验数字,不是数学公式,极端场景可能超出范围。

权衡一:为什么选 1s 而不是 0.5s?
500~1000ms 是 0.5s 和 1.0s 的兜底能力分水岭:
低于 500ms 两者都能兜;高于 1000ms 两者都兜不住(该用显式等待);
只有在 500~1000ms 之间,1.0s 比 0.5s 多出了实际价值: 代价对比(和显式等待 explicit=15s 混用时):
0.5s 叠加成本 = 0.5 × 30 = 15 秒 
1.0s 叠加成本 = 1.0 × 30 = 30 秒(多 15 秒)

→ 多花 15 秒叠加成本,换 500~1000ms 档竞态(race condition)的兜底覆盖。这是一个合理的折中,不是数学必然。
权衡二:为什么不设 2s?
2s 的兜底窗口确实更大,但代价全部翻倍,而兜底提升边际效益递减:

① 叠加变长成本:和显式等待混用时的最坏耗时公式:
最坏 = implicit × (explicit超时 / pollFreq)
注:这里的 pollFreq 是 显式等待 WebDriverWait 的 poll_frequency(Selenium Python 客户端默认 500ms,硬编码在 wait.py 里),不是隐式等待的轮询间隔。这个值是确定的。

假设 explicit=15s、pollFreq=0.5s:
implicit=1s → 1 × 30 = 30 秒 ✅ 可接受
implicit=2s → 2 × 30 = 60 秒 ⚠️ 翻倍(多 30 秒,兜底窗口只多 1000ms)
implicit=5s → 5 × 30 = 150 秒 💀 爆炸

② "确认元素不存在"的白等:你写了 10 个 try: find_element ... except NoSuchElementException:
implicit=1s → 白等 10 秒
implicit=2s → 白等 20 秒(翻倍)
implicit=5s → 白等 50 秒(爆炸)

竞态(race condition)通常差 200~500ms,1s 的兜底窗口完全兜得住绝大多数。
从 1s 升到 2s,兜底窗口只多了 1000ms,但叠加成本和白等全部翻倍——边际效益递减太明显。
✅ 最终结论
值 兜底窗口
(规范定义)
叠加成本
explicit=15s
白等
10次不存在
依据类型 推荐
不设(=0)0ms0 秒0 秒规范最严谨
1s1000ms30 秒10 秒经验+权衡默认推荐
0.5s500ms15 秒5 秒经验+权衡确认页面 <500ms
2s2000ms60 秒20 秒代价太大谨慎
≥5s≥5000ms150 秒+50 秒+爆炸❌ 绝对避免