Playwright启动浏览器必须显式设置headless=True,因新版本默认启用GUI模式,服务器无图形界面会导致卡住或超时;本地调试可用headless=False配合slow_mo=500观察。

Playwright 启动浏览器时必须显式指定 headless 模式
Python 3.11 下 Playwright 默认行为没变,但很多新手直接调 playwright.chromium.launch() 却卡住或报超时——根本原因是新版本默认启用 GUI 模式,而服务器环境没图形界面。不加 headless=True 就会等一个永远打不开的窗口。
实操建议:
- 本地调试可设
headless=False,但务必加slow_mo=500方便观察;生产环境一律用headless=True - 若仍报
BrowserType.launch: Executable doesn't exist,先运行playwright install chromium(不是 pip install) - 避免用
chromium别名,明确写playwright.chromium,防止多浏览器安装后自动 fallback 到不兼容的引擎
等待异步内容加载不能只靠 page.wait_for_timeout()
page.wait_for_timeout(3000) 是最常见也最危险的写法:它不判断内容是否真就位,只是盲等。JS 渲染可能 200ms 完成,也可能因网络卡在 3500ms,结果要么浪费时间,要么拿不到数据。
正确做法是绑定到真实 DOM 变化:
立即学习“Python免费学习笔记(深入)”;
- 用
page.wait_for_selector("article.product-item", state="visible")等关键元素出现 - 若页面用 React/Vue,且内容由 JS 动态注入,优先监听
page.evaluate("window.__NEXT_DATA__")或类似全局状态变量是否就绪 - 遇到滚动触底加载,先
page.evaluate("window.scrollTo(0, document.body.scrollHeight)"),再page.wait_for_function('document.querySelectorAll(".item").length > 10')
处理登录态和请求拦截时,context.add_cookies() 必须在 new_page() 前调用
想复用已登录的 session?很多人把 context.add_cookies(cookies) 放在 context.new_page() 之后,结果新页面完全没带上 cookie——因为 Playwright 的 cookie 是绑定到 context 生命周期的,页面创建后才加,对当前页无效。
关键顺序:
- 先
context = browser.new_context() - 立刻
context.add_cookies([{"name": "sessionid", "value": "...", "domain": ".example.com", "path": "/"}])(注意 domain 和 path 必须精确匹配) - 再
page = context.new_page() - 如果要绕过登录页直接进首页,记得加
ignore_https_errors=True,否则自签名证书会中断流程
导出数据时别用 page.content() 直接取整页 HTML
page.content() 返回的是初始 HTML,不含 JS 渲染后的 DOM 变更。比如商品价格显示为 $0.00,实际渲染后变成 $299.99,用 content() 就抓错。
该用什么:
- 取结构化数据:用
page.query_selector_all("div.price")+.inner_text()或.get_attribute("data-price") - 需要完整渲染后 HTML:用
page.eval_on_selector("body", "el => el.outerHTML"),它执行在页面上下文,能拿到最终 DOM - 若目标是截图或 PDF,直接
page.screenshot(path="out.png", full_page=True),别自己拼 HTML 再转
真正麻烦的是那些用 IntersectionObserver + requestIdleCallback 做懒加载的页面——它们根本不触发传统 scroll 事件,得用 page.evaluate() 主动调用 requestIdleCallback 回调或伪造滚动帧,这点很容易被忽略。


















