playwright自动等待机制省去了selenium中必须手动编写的webdriverwait显式等待或time.sleep()隐式等待代码,它默认对click、fill等操作智能检测元素存在、可见、稳定、可交互等全部就绪条件,无需额外等待逻辑即可稳定执行。

Playwright 的自动等待机制到底省了什么?
Selenium 必须靠 WebDriverWait 或 time.sleep() 控制节奏,但前者要写条件、设超时、处理异常,后者纯靠猜——页面加载快了会报 ElementNotInteractableError,慢了又拖慢整体速度。Playwright 的 page.click()、page.fill() 等所有操作默认自带“就绪检测”:它会等元素存在、可见、稳定、可点击、无遮挡、事件绑定完成,全部满足才执行。
- 这不是轮询,而是监听浏览器 DevTools Protocol 的 DOM 和 JS 执行状态
- 不需要你写 wait_for_selector 除非真有特殊时机要求(比如等某个异步请求返回后才出现的按钮)
- 实测中,一个含 5 个动态加载区块的页面,Selenium 平均要写 3~4 处显式等待,Playwright 零等待代码也能稳定通过
通信协议差异直接拉开了响应延迟
Selenium 走的是 HTTP + JSON Wire Protocol,每次操作都要发一次请求、等响应、再发下一次,中间还要经过 chromedriver 这个独立进程转发。Playwright 直连浏览器内核,用 WebSocket 建立长连接,指令下发和状态回传是双向实时的。
- 同样执行 page.goto() → page.locator("button").click(),Selenium 平均多出 40–60ms 的通信开销
- 在 CI/CD 流水线里跑 200 个用例,这部分延迟累计可达 10+ 秒
- 更关键的是:Selenium 的 HTTP 请求可能被防火墙或代理拦截,而 WebSocket 更难被识别为自动化流量
BrowserContext 比多开浏览器实例更轻量
Selenium 想隔离登录态或 Cookie,只能开多个 webdriver.Chrome() 实例,每个都吃内存、占端口、启动慢。Playwright 的 browser.new_context() 是在单个浏览器进程中创建沙箱环境:
- 每个 BrowserContext 有独立的 Cookie、LocalStorage、缓存、权限策略
- 启动耗时不到 Selenium 单实例的 1/3,内存占用通常只有 1/5
- 支持 context.add_init_script() 注入全局脚本,比如统一屏蔽 navigator.webdriver,比 Selenium 里 patch chromedriver 稳定得多
定位失败率低,不是因为 selector 更强,而是因为时机更准
很多人以为 Playwright 定位准是因为支持 text= 或 role= 等新语法,其实核心在于:它不只查 DOM 是否存在,还查“这个元素此刻是否能被用户真正交互”。
- Selenium 定位到一个 DOM 节点后立刻点击,但此时它可能还在动画中、被 loading 遮罩、或 JS 尚未绑定 click 事件
- Playwright 的 locator.click() 会等到这些前置条件全部就绪,失败时自动重试(默认 30 秒超时,可调)
- 实际爬取 SPA 页面时,Selenium 报 TimeoutException 的地方,Playwright 往往静默通过——你甚至意识不到它刚帮你躲过了一次渲染竞态
HTTP + JSON Wire Protocol,每次操作都要发一次请求、等响应、再发下一次,中间还要经过 chromedriver 这个独立进程转发。Playwright 直连浏览器内核,用 WebSocket 建立长连接,指令下发和状态回传是双向实时的。
- 同样执行 page.goto() → page.locator("button").click(),Selenium 平均多出 40–60ms 的通信开销
- 在 CI/CD 流水线里跑 200 个用例,这部分延迟累计可达 10+ 秒
- 更关键的是:Selenium 的 HTTP 请求可能被防火墙或代理拦截,而 WebSocket 更难被识别为自动化流量
BrowserContext 比多开浏览器实例更轻量
Selenium 想隔离登录态或 Cookie,只能开多个 webdriver.Chrome() 实例,每个都吃内存、占端口、启动慢。Playwright 的 browser.new_context() 是在单个浏览器进程中创建沙箱环境:
- 每个 BrowserContext 有独立的 Cookie、LocalStorage、缓存、权限策略
- 启动耗时不到 Selenium 单实例的 1/3,内存占用通常只有 1/5
- 支持 context.add_init_script() 注入全局脚本,比如统一屏蔽 navigator.webdriver,比 Selenium 里 patch chromedriver 稳定得多
定位失败率低,不是因为 selector 更强,而是因为时机更准
很多人以为 Playwright 定位准是因为支持 text= 或 role= 等新语法,其实核心在于:它不只查 DOM 是否存在,还查“这个元素此刻是否能被用户真正交互”。
- Selenium 定位到一个 DOM 节点后立刻点击,但此时它可能还在动画中、被 loading 遮罩、或 JS 尚未绑定 click 事件
- Playwright 的 locator.click() 会等到这些前置条件全部就绪,失败时自动重试(默认 30 秒超时,可调)
- 实际爬取 SPA 页面时,Selenium 报 TimeoutException 的地方,Playwright 往往静默通过——你甚至意识不到它刚帮你躲过了一次渲染竞态
text= 或 role= 等新语法,其实核心在于:它不只查 DOM 是否存在,还查“这个元素此刻是否能被用户真正交互”。
- Selenium 定位到一个 DOM 节点后立刻点击,但此时它可能还在动画中、被 loading 遮罩、或 JS 尚未绑定 click 事件
- Playwright 的 locator.click() 会等到这些前置条件全部就绪,失败时自动重试(默认 30 秒超时,可调)
- 实际爬取 SPA 页面时,Selenium 报 TimeoutException 的地方,Playwright 往往静默通过——你甚至意识不到它刚帮你躲过了一次渲染竞态
真正容易被忽略的是:Playwright 的高效不是靠“更快地犯错然后重试”,而是从第一行代码开始就减少了出错可能性。它把大量隐式依赖(如页面加载完成、JS 初始化完毕、网络请求返回)变成了显式契约,而这个契约由浏览器内核本身保证,不是靠人猜。











