前言

        Selenium 对于 UI 自动化,就像是内功对于 “古典武学”,招式可以变(Cypress/Playwright),但内功(WebDriver 协议)是通用的。

        尽管对于 AI 而言更青睐 Playwright 与 AgentBrowser,这让 Selenium 在 AI 时代略显尴尬,但作为历经多年沉淀的技术,其庞大的应用体量仍能让我们借此感受浏览器自动化的魅力。而且对于部分公司的 UI 自动化测试平台而言,Selenium 已运行稳定,因此它依旧占据一席之地,掌握它对于我们测试人员而言,堪称技术基石。


核心架构与环境准备

忘掉手动下载 chromedriver.exe 的上古做法。2026 年的标准实践强调自动化管理与环境隔离。

核心架构:三层模型

脚本层(Script)

        你的 Python/Java 代码,通过 W3C WebDriver 协议发送 JSON 指令。

WebDriver 服务层(Service)

        Selenium 4 彻底废弃 JSON Wire Protocol,全面拥抱 W3C。ChromeDriver 等作为独立服务运行,与浏览器通过 HTTP/JSON 通信,响应更稳定。

浏览器层 (Browser)

        真正的执行端。

环境搭建

语言环境

        Python 3.9+ (推荐 3.10/3.11),使用 venv 创建隔离环境,避免包冲突。

安装

pip install selenium

驱动管理

首选方案

        webdriver-manager 库。它能自动检测本地浏览器版本并下载匹配驱动。

from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager

service = ChromeService(executable_path=ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
注意

        在大多数公网环境下,这能显著改善驱动匹配问题。但在企业内网或特殊定制浏览器环境中,可能需要配置代理或手动指定镜像源。

备选方案

        Selenium Manager CLI。如果 webdriver-manager 失效,新版 Selenium 自带的 SeleniumManager 会尝试自动下载驱动,无需代码引入第三方库。

兜底方案

        在严格的离线环境中,需将驱动二进制文件放入系统 PATH,或通过 Docker 镜像固化环境。


实战精髓——从 “脚本仔” 到 “测试开发” 的必经之路

元素定位

定位优先级(从高到低,基于稳定性与性能)

1.ID / Name:唯一且通常不随样式改变。

username_input = driver.find_element(By.ID, "user-login-id")

2.CSS Selector:企业级首选。速度快、语法简洁、浏览器原生支持好。
推荐:#id, .class, input[name='phone'], div > p (父子关系)。

phone_input = driver.find_element(By.CSS_SELECTOR, "input[name='phone']")

3.XPath:最后手段。功能最强但速度慢、可读性差。严禁使用绝对路径(如 /html/body/div[1]...)。仅在需要跨越 iframe 或根据文本内容查找时使用。

submit_btn = driver.find_element(By.XPATH, "//button[text()='立即登录']")

4.Selenium 4 革命性特性:相对定位器 (Relative Locators):当前必须掌握。基于元素间的视觉关系(上下左右、邻近)定位,极大提升健壮性。

from selenium.webdriver.support.locators import with_tag_name
from selenium.webdriver.support.relative_locator import locate_with

# 找到 "password" 输入框下方的 "submit" 按钮
password_field = driver.find_element(By.ID, "password")
submit_button = driver.find_element(locate_with(By.TAG_NAME, "button").below(password_field))

等待机制

行业铁律:永远、永远不要使用 time.sleep()! 这会导致测试时间不可控,且在 CI/CD 中极不可靠。

全局隐式等待 (Implicit Wait)

        作为基础保障,设置一次即可(通常 5-10 秒),用于应对网络延迟。

driver.implicitly_wait(10)

显式等待 (Explicit Wait)

        针对特定元素、特定状态进行精准等待。

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

# 等待按钮变为“可点击”状态,最长等待10秒
submit_btn = WebDriverWait(driver, 10).until(
    EC.element_to_be_clickable((By.ID, "submit-btn"))
)
submit_btn.click()

显示等待中常见的 expected_conditions

架构设计:页面对象模型 (POM)

这是从 “写脚本” 到 “做框架” 的分水岭。

为什么必须用 POM?

POM 最佳实践结构

project/
├── pages/              # 页面对象层
   ├── base_page.py    # 封装通用方法 (find, click, wait)
   └── login_page.py   # 登录页元素与操作
├── tests/              # 测试用例层 (只关心业务)
   └── test_login.py
├── data/               # 测试数据分离
   └── login_data.yaml
└── conftest.py         # Pytest Fixture (管理 driver 生命周期)

login_page.py 示例

from selenium.webdriver.common.by import By
from .base_page import BasePage

class LoginPage(BasePage):
    # 元素定位器私有化
    _username_input = (By.ID, "username")
    _password_input = (By.ID, "password")
    _submit_btn = (By.CSS_SELECTOR, "button[type='submit']")

    def enter_username(self, username):
        self.find_element(self._username_input).send_keys(username)

    def enter_password(self, password):
        self.find_element(self._password_input).send_keys(password)

    def click_submit(self):
        self.find_element(self._submit_btn).click()

    # 业务操作封装
    def login(self, username, password):
        self.enter_username(username)
        self.enter_password(password)
        self.click_submit()
        # 返回下一个页面的对象 (链式调用)
        from .home_page import HomePage
        return HomePage(self.driver)

后记

        回忆起上一家公司,笔者就参与到了 UI 自动化平台的搭建,也是使用的 Selenium,所以不言而喻 Selenium 是笔者的白月光。即使是后来接触到了 Playwright,以及 AgentBrowser,情感依旧是抵不过 Selenium,毕竟前两者技术在笔者看来发展的逐渐趋势是对 AI 友好,而后者依旧是对人类友好。


↙↙↙阅读原文可查看相关链接,并与作者交流