Selenium WebDriver 是 Python 浏览器自动化的核心入口。它通过浏览器原生自动化接口打开页面、查找元素并执行交互,WebDriver 属于 W3C 标准,因此同一套思路可迁移到 Chrome、Firefox、Edge、Safari。它常用于端到端测试、跨浏览器验证、重复性后台操作,以及依赖真实浏览器行为的网页流程。Selenium 不会自动判断页面是否正确,关键行为仍需要编写清晰断言。
工作链路可以理解为:Python 测试脚本 -> Selenium WebDriver -> 浏览器驱动 / Selenium Manager -> 浏览器。脚本通过 Selenium 语言绑定发出命令,浏览器驱动负责把命令交给具体浏览器并返回结果。较新的 Selenium 绑定可通过 Selenium Manager 协助管理驱动,减少手动下载和版本匹配;但运行环境仍需安装受支持的浏览器,并允许相应驱动管理流程完成。Selenium 项目还包含 Selenium IDE 和 Selenium Grid,前者用于录制回放,后者用于远程及并行浏览器执行,不要把它们的职责与 WebDriver 混为一谈。
准备 Python 环境
建议在项目虚拟环境中安装 Selenium:- python -m venv .venv
- # macOS / Linux
- source .venv/bin/activate
- # Windows PowerShell 可使用:.venv\Scripts\Activate.ps1
- python -m pip install selenium
复制代码 确认本机已安装计划测试的浏览器。对于较新的 Selenium,通常可以先尝试直接启动浏览器;如果网络策略、浏览器版本或企业环境限制导致自动管理失败,再根据官方文档配置对应驱动。
第一个完整示例
下面的脚本访问 Selenium 官方演示页,输入搜索词并验证页面标题。它覆盖建立会话、定位元素、等待页面状态、执行操作、断言结果,并在结束时关闭浏览器:- from selenium import webdriver
- from selenium.webdriver.common.by import By
- from selenium.webdriver.support import expected_conditions as EC
- from selenium.webdriver.support.ui import WebDriverWait
- driver = webdriver.Chrome()
- wait = WebDriverWait(driver, 10)
- try:
- driver.get('https://www.selenium.dev/selenium/web/web-form.html')
- text_box = wait.until(
- EC.visibility_of_element_located((By.NAME, 'my-text'))
- )
- text_box.send_keys('Selenium WebDriver')
- driver.find_element(By.CSS_SELECTOR, 'button').click()
- message = wait.until(
- EC.visibility_of_element_located((By.ID, 'message'))
- )
- assert message.text == 'Received!'
- print('表单提交成功:', message.text)
- finally:
- driver.quit()
复制代码 try/finally 能确保即使断言失败也会退出浏览器会话。真实项目中,常把创建和清理逻辑放进 pytest fixture,让每个测试获得独立、可预期的浏览器状态。
元素定位:稳定性从这里开始
Selenium 提供 ID、名称、CSS 选择器、XPath、链接文字等定位方式。优先选择唯一、语义清晰且不容易随布局变化的属性。如果你能影响应用代码,为关键控件添加稳定的 data-testid 往往很有帮助。- from selenium.webdriver.common.by import By
- submit = driver.find_element(By.ID, 'submit')
- email = driver.find_element(By.NAME, 'email')
- save = driver.find_element(By.CSS_SELECTOR, "button[data-testid='save']")
复制代码 可以把定位器集中定义,让页面结构变化时更容易维护:- class LoginPage:
- EMAIL = (By.NAME, 'email')
- PASSWORD = (By.NAME, 'password')
- SUBMIT = (By.CSS_SELECTOR, "button[data-testid='login']")
复制代码 XPath 适合 CSS 难以表达的关系或文本场景,但复杂、依赖页面层级的 XPath 往往很脆弱。应避免使用“页面第 3 个 div 下面的第 2 个按钮”这类只描述当前布局的定位器。
等待动态页面,而不是猜时间
现代网页经常在首屏加载后继续通过 JavaScript 更新内容。driver.get() 返回并不代表目标控件已经可交互。固定的 time.sleep(5) 每次都浪费时间,而且网络或机器变慢时仍可能失败。更好的做法是等待具体条件:- wait = WebDriverWait(driver, 10)
- button = wait.until(
- EC.element_to_be_clickable((By.ID, 'continue'))
- )
- button.click()
复制代码 常用条件包括元素可见、元素可点击、元素存在、文字出现以及页面标题匹配。隐式等待是针对元素查找的全局设置;显式等待则能准确描述当前步骤所需要的状态。不要混用隐式等待和显式等待,否则实际等待时间可能难以预测。
常见交互与浏览器控制- # 文本框
- search = driver.find_element(By.NAME, 'q')
- search.clear()
- search.send_keys('browser automation')
- # 下拉框(原生 select)
- from selenium.webdriver.support.ui import Select
- Select(driver.find_element(By.ID, 'country')).select_by_value('cn')
- # 截图与窗口
- driver.save_screenshot('failure.png')
- driver.maximize_window()
复制代码 复选框、单选框和按钮通常可以用 click() 操作;文件上传通常通过向 file 类型输入框发送文件路径完成。对于新窗口、iframe、悬停和键盘组合等场景,应先显式切换到正确的窗口或 frame,再执行定位和交互。操作之后最好等待可观察的页面变化,而不是假设点击必然成功。
让测试更可靠的实践
断言用户可见的结果。点击成功不等于业务操作成功;检查确认信息、状态变化或导航结果。每个测试独立准备状态,避免测试间依赖执行顺序或共享浏览器残留数据。采用 Page Object 管理复杂页面,把定位器和页面操作封装起来,让测试用业务语言表达意图。保留失败证据,失败时收集截图、当前 URL、控制台日志和必要的页面信息,缩短排查时间。优先修复不稳定根因,如果测试偶发失败,检查等待条件、定位器稳定性、测试数据和环境差异,不要只增加超时时间。把浏览器和测试环境版本纳入 CI,本地通过、流水线失败常常来自浏览器版本、网络、并发或数据隔离差异。
一个好的测试读起来像一段可验证的用户旅程:准备 → 操作 → 等待 → 断言 → 清理。
从本机走向并行执行
当测试需要覆盖多种浏览器,或希望在 CI 中并行运行时,可以考虑 Selenium Grid。Grid 让测试代码连接远端执行环境,由其分配浏览器会话。扩展之前,先保证单个测试可重复、数据互不干扰,并设置合理的超时和失败诊断;并行会放大测试本身的竞态问题。
Selenium 也在推进 WebDriver BiDi,用于双向、事件驱动的浏览器通信,例如订阅网络或控制台事件。具体能力会随浏览器和 Selenium 版本而异,使用前请查看官方文档的支持情况。
适用边界与总结
如果目标是验证真实浏览器中的用户流程,Selenium 是成熟且跨浏览器的选择。如果只需快速请求静态页面,直接使用 HTTP 客户端通常更简单;若测试侧重组件内部逻辑,则单元测试往往更快、更聚焦。合理的测试组合会让端到端测试覆盖关键路径,而不是承担所有验证工作。
记住三件事:用稳定定位器找到元素,用显式等待描述页面状态,用断言验证用户结果。做到这三点,你的 Selenium 脚本就会从“能跑一次”逐渐变成团队可以长期维护的测试资产。 |