作者:测开老王
---
前言
大家好,我是测开老王。做自动化测试7年,Selenium用了5年多,见证了它从2.x到4.x的演变。今天这篇,我想系统聊聊Selenium 4的新特性,以及在实际项目中的应用。
Selenium 4在2021年底正式发布,相比3.x版本,变化很大:
完全支持W3C标准协议
全新的Relative Locator(相对定位器)
重构的Grid架构
更好的Chrome DevTools支持
窗口管理API增强
这些变化对我们写自动化脚本有什么影响?下面一一分析。
---
一、W3C协议:告别JSON Wire Protocol
什么是W3C协议?
在Selenium 3时代,WebDriver使用的是JSON Wire Protocol,这是Selenium自定义的协议。不同浏览器厂商需要实现自己的Driver(如chromedriver、geckodriver),协议实现有差异,导致一些兼容性问题。
Selenium 4采用了W3C WebDriver标准协议,这意味着:
浏览器Driver实现更统一
API行为更一致
跨浏览器测试更稳定
对我们有什么影响?
好消息:
现有脚本基本不用改 。Selenium 4向后兼容,大部分API保持不变。
但有一些细节需要注意:
`python
Selenium 3 的写法(仍然支持)
driver.find_element_by_id("username")
driver.find_element_by_css_selector(".btn-primary")
Selenium 4 推荐的写法
from selenium.webdriver.common.by import By
driver.find_element(By.ID, "username")
driver.find_element(By.CSS_SELECTOR, ".btn-primary")
`
旧方法会显示DeprecationWarning,建议统一改成新写法。
实际踩坑
我在升级一个老项目时,遇到一个问题:
`python
这行代码在Selenium 3可以运行
element = driver.find_element_by_xpath("//div[@class='content']")
Selenium 4 会报警告
DeprecationWarning: find_element_by_* is deprecated. Please use find_element() instead
`
解决方案 :写一个兼容层脚本,批量替换旧方法。
`python
兼容层示例
def find_by_id(driver, element_id):
return driver.find_element(By.ID, element_id)
def find_by_xpath(driver, xpath):
return driver.find_element(By.XPATH, xpath)
`
---
二、Relative Locator:革命性的定位方式
这是Selenium 4最让人兴奋的新特性!
传统定位的痛点
以前定位元素,只能用:
ID、Name、ClassName
XPath、CSS Selector
LinkText、PartialLinkText
但这些定位器都是基于元素自身的属性。如果元素没有ID、没有稳定的class,XPath又很长很脆弱,怎么办?
Relative Locator登场
Relative Locator允许我们根据元素之间的空间关系来定位:
above() - 在某元素上方
below() - 在某元素下方
toLeftOf() - 在某元素左侧
toRightOf() - 在某元素右侧
near() - 在某元素附近
实战示例
假设有一个登录表单:
`html
登录
`
输入框没有ID,class也是动态生成的。用传统方式定位很麻烦。
用Relative Locator:
`python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.relative_locator import locate_with
driver = webdriver.Chrome()
driver.get("https://example.com/login")
先定位Logo
logo = driver.find_element(By.TAG_NAME, "img")
定位用户名输入框(在Logo下方)
username = driver.find_element(locate_with(By.TAG_NAME, "input").below(logo))
定位密码输入框(在用户名下方)
password = driver.find_element(locate_with(By.TAG_NAME, "input").below(username))
定位登录按钮(在密码下方)
login_btn = driver.find_element(locate_with(By.TAG_NAME, "button").below(password))
`
组合使用
Relative Locator可以组合使用:
`python
from selenium.webdriver.support.relative_locator import locate_with
定位在Logo下方、且在右侧栏内的元素
element = driver.find_element(
locate_with(By.TAG_NAME, "input")
.below(logo)
.to_right_of(sidebar)
)
`
使用场景
Relative Locator特别适合这些场景:
1.
表单布局固定但元素属性不稳定
- 输入框没有固定ID
- 根据Label文本定位旁边输入框
2.
响应式布局测试
- 不同屏幕尺寸下元素位置变化
- 相对位置关系保持不变
3.
动态内容页面
- 列表项没有固定属性
- 但相对位置关系稳定
注意事项
Relative Locator依赖元素在页面上的实际位置
元素不可见时定位会失败
复杂布局可能有歧义(比如多个元素都符合条件)
---
三、WebDriverManager自动管理Driver
Selenium 4不再内置Driver管理,推荐使用WebDriverManager。
以前的痛点
`python
以前需要手动下载chromedriver,放到指定路径
driver = webdriver.Chrome("/path/to/chromedriver")
问题:
1. Chrome更新后,Driver版本不匹配
2. 不同环境路径不同
3. CI/CD环境配置麻烦
`
现在的解决方案
`python
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
自动下载和管理Driver
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
`
WebDriverManager会:
自动检测浏览器版本
下载匹配的Driver
缓存到本地,不用重复下载
---
四、Chrome DevTools支持
Selenium 4可以直接调用Chrome DevTools协议,实现更强大的功能。
模拟网络条件
`python
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
driver = webdriver.Chrome()
启用网络模拟
driver.execute_cdp_cmd("Network.enable", {})
模拟3G网络
driver.execute_cdp_cmd("Network.emulateNetworkConditions", {
"offline": False,
"latency": 100, # 延迟100ms
"downloadThroughput": 500 * 1024, # 下载速度 500KB/s
"uploadThroughput": 500 * 1024, # 上传速度 500KB/s
})
driver.get("https://example.com")
`
模拟地理位置
`python
模拟GPS位置
driver.execute_cdp_cmd("Emulation.setGeolocationOverride", {
"latitude": 39.9042, # 北京
"longitude": 116.4074,
"accuracy": 100
})
driver.get("https://example.com/map")
`
截取特定元素
`python
截取特定元素的截图
element = driver.find_element(By.ID, "chart")
screenshot = element.screenshot_as_png
with open("chart.png", "wb") as f:
f.write(screenshot)
`
---
五、窗口管理增强
Selenium 4新增了窗口管理API:
`python
创建新标签页
driver.switch_to.new_window("tab")
创建新窗口
driver.switch_to.new_window("window")
获取窗口信息
window_rect = driver.get_window_rect()
print(window_rect) # {'x': 10, 'y': 10, 'width': 1200, 'height': 800}
设置窗口位置和大小
driver.set_window_rect(x=100, y=100, width=1024, height=768)
最小化窗口
driver.minimize_window()
全屏
driver.fullscreen_window()
`
---
六、Grid 4架构重构
Selenium Grid 4完全重构了架构:
新架构组件
Router :接收请求,分发到对应组件
Distributor :选择合适的Node执行测试
Session Map :存储Session与Node的映射关系
Session Queue :新Session请求队列
Nodes :实际执行测试的节点
启动Standalone模式
`bash
java -jar selenium-server-4.x.jar standalone
`
启动Hub-Node模式
`bash
启动Hub
java -jar selenium-server-4.x.jar hub
启动Node(连接到Hub)
java -jar selenium-server-4.x.jar node --hub http://hub-ip:4444
`
Docker部署
`bash
启动Standalone
docker run -d -p 4444:4444 selenium/standalone-chrome
启动Hub
docker run -d -p 4444:4444 selenium/hub
启动Node
docker run -d --net host selenium/node-chrome
`
---
七、实战:Selenium 4自动化框架模板
下面是一个基于Selenium 4 + Pytest的自动化框架示例:
`python
conftest.py
import pytest
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
@pytest.fixture(scope="function")
def driver():
"""初始化WebDriver"""
options = webdriver.ChromeOptions()
options.add_argument("--headless") # 无头模式
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
driver = webdriver.Chrome(
service=Service(ChromeDriverManager().install()),
options=options
)
driver.maximize_window()
yield driver
driver.quit()
test_login.py
from selenium.webdriver.common.by import By
from selenium.webdriver.support.relative_locator import locate_with
def test_login(driver):
"""测试登录功能"""
driver.get("https://example.com/login")
# 使用Relative Locator定位
logo = driver.find_element(By.TAG_NAME, "img")
username = driver.find_element(locate_with(By.TAG_NAME, "input").below(logo))
password = driver.find_element(locate_with(By.TAG_NAME, "input").below(username))
username.send_keys("testuser")
password.send_keys("password123")
login_btn = driver.find_element(By.CSS_SELECTOR, "button[type='submit']")
login_btn.click()
# 验证登录成功
assert "dashboard" in driver.current_url
`
---
八、升级建议
如果你的项目还在用Selenium 3,升级到4的建议:
1.
先升级依赖
`bash
pip install selenium==4.x.x
pip install webdriver-manager
`
2.
更新定位器写法
- 全局搜索
find_element_by_
- 替换为
find_element(By.*, ...)
3.
测试Relative Locator
- 找几个复杂定位场景
- 尝试用Relative Locator简化
4.
评估Grid升级
- 如果用了Grid,评估是否升级到4.x
- Docker部署更简单
---
总结
Selenium 4是一次重要的版本升级,主要收益:
| 特性 | 收益 |
|------|------|
| W3C协议 | 跨浏览器兼容性更好 |
| Relative Locator | 定位元素更灵活 |
| DevTools支持 | 网络模拟、地理位置等高级功能 |
| Grid重构 | 分布式测试更易部署 |
| API现代化 | 代码更规范、可维护 |
对于新项目,建议直接用Selenium 4。老项目升级风险不大,API兼容性很好。
---
参考资料
Selenium官方文档:https://www.selenium.dev/documentation/
Selenium 4 Release Notes:https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG
WebDriver W3C标准:https://w3c.github.io/webdriver/
RunnerGo博客:https://www.runnergo.com/blog/
---
下期预告:Playwright vs Cypress对决 - 2026年最值得学习的自动化测试框架
作者:测开老王,7年测试开发经验,专注Web自动化和测试框架设计。公众号:测开那些事儿