先说结论:如果你手上的项目还是 Selenium 3.x,先别急着升 4。我上周把一个 2019 年的老项目从 3.141.59 升到 4.27,两天时间,一半花在改 API,一半花在跟 Grid 的 session 超时较劲。
但真正让我血压上来的是另一件事。同一份用例,本地跑 8 分 12 秒,扔到 CI 上跑 47 分 03 秒。我用 pytest --durations=20 一拉,前 20 个最慢的用例全是登录、搜索这种最简单的操作。
隐式等待和显式等待,别一起用
去翻代码,找到了这行:
driver.implicitly_wait(10)
在 conftest.py 的 fixture 里,全局生效。然后业务代码里到处都是:
WebDriverWait(driver, 5).until(
EC.element_to_be_clickable((By.ID, "submit"))
)
看起来没问题,官方文档也说了两者可以共存。但实际行为是:隐式等待不影响显式等待的超时时间,却会影响显式等待内部每一次 find_element 调用的耗时。
显式等待是轮询机制,默认 polling_frequency 是 500ms。每次轮询会执行一次 driver.find_element。而此刻隐式等待是 10 秒,意味着这一次 find_element 如果没找到元素,会先老老实实等满 10 秒才抛 NoSuchElementException,然后显式等待才发现——哦,超时了,或者继续下一次轮询。
结果就是:一个本该在 5 秒后超时的 WebDriverWait,实际可能耗掉 15 秒甚至更久。30 个这种等待,一个用例多花 5 分钟,200 条用例的回归集,时间就是这么涨上去的。
修复很简单,把 implicitly_wait 去掉,全部改用显式等待。改完再跑:本地 7 分 45 秒,CI 11 分 20 秒。对,47 分钟降到 11 分钟。剩下那 3 分多钟是 CI 机器本身比本地慢,可以接受。
Selenium 4 真正的更新,只有两个值得关注
Selenium 4 的更新日志很长,W3C 协议标准化、相对定位器、CDP 支持、Grid 重写。但挑两个真正影响日常写代码的:
第一个是 Selenium Manager。 从 4.6 开始,不需要再装 webdriver-manager 或手动下载 chromedriver 了。以前 CI 上最常见的报错是:
SessionNotCreatedException: session not created:
This version of ChromeDriver only supports Chrome version 114
现在只要 Chrome 是当前版本,Selenium 会自动匹配 driver。当然也有坑——公司内网隔离环境下载不了 driver,这时还是得手动指定 Service(executable_path=...)。
第二个是相对定位器。 above、below、toLeftOf、toRightOf、near 这五个。听起来美好,我在实际项目里一次都没用过。原因很现实:这些定位器依赖元素的视觉位置,前端改个 padding 就可能让它失效。倒不如老老实实用 data-testid。
顺便说个容易忽略的:page_load_strategy 有三个值,normal、eager、none。默认 normal 会等所有资源加载完,在我那个项目里,光是把策略从 normal 改成 eager,单条用例就省了 1.8 秒左右。
什么情况下我会劝你放弃 Selenium
这话题容易吵架,我说我的判断标准。
如果你做的是面向浏览器的自动化测试,且团队用 Python,那 Playwright 在这几个场景下确实更省心:
- 等待机制。Playwright 的 auto-waiting 是内建的,click、fill 自带可操作性检查。你不用写 WebDriverWait,也就不会踩上面那个坑。
- iframe 和 shadow DOM。Selenium 里切 iframe 要
switch_to.frame(),切回来还要switch_to.default_content(),嵌套三层就疯了。Playwright 的 locator 可以直接穿透。 - 网络拦截。Selenium 4 虽然能通过 CDP 做,但 API 是
execute_cdp_cmd,写起来很别扭。
但反过来,这几种情况我还是留在 Selenium:
- 需要跑在真实设备农场,比如 BrowserStack 或公司自建的真机集群,Selenium 的兼容性最好。
- Java 技术栈。Playwright 的 Java 版能用,但生态和文档量跟 Selenium 差一个量级。
- 已经在维护的存量用例,几千条那种。迁移成本远大于收益,除非重构,否则别动。
最后
说个数据。GitHub 上:seleniumhq/selenium 大约 3 万 star,microsoft/playwright 大约 6.8 万。但 PyPI 下载量反过来,selenium 是每周千万级别,playwright 还是百万级别。
这个差距说明什么?存量项目的惯性。2020 年之前建的测试框架,几乎清一色 Selenium。这些不会因为 Playwright 好用就消失。
所以我的建议是:新项目可以直接上 Playwright。老项目,先解决隐式等待这种性能问题,别折腾迁移。至于要不要学 Selenium——面试还是会问的。