Playwright 多浏览器实例不能真正并发,应复用单个浏览器的多个 Page 并配合 async_playwright() 与 asyncio;需绕过无头检测、控制并发数、合理截图并及时释放资源。

Playwright 多浏览器实例是否真能并发?
不能直接用多个 sync_playwright() 上下文实现高并发,因为每个上下文启动的是独立浏览器进程,开销大、内存占用高、容易被目标网站识别为异常流量。真正的并发应该复用单个浏览器实例的多个 Page,并配合异步 I/O 控制节奏。
- 必须用
async_playwright()+asyncio,同步模式天然阻塞,无法并发 - 一个
browser实例可创建几十个page,但实际建议控制在 5–15 个并发page.goto(),否则容易触发 Cloudflare 验证或超时 - 不要为每个 URL 启动新浏览器——
playwright.chromium.launch(headless=True)只调用一次
截图前必须绕过哪些常见拦截?
多数网站对无头浏览器有强检测,Playwright 默认行为很容易被 document.visibilityState、navigator.webdriver 或 canvas 指纹识别拦截,导致白屏或跳转到验证页。
- 启动浏览器时加
args=["--disable-blink-features=AutomationControlled"] - 注入 JS 覆盖关键属性:
await page.add_init_script("Object.defineProperty(navigator, 'webdriver', {value: undefined})") - 设置真实 UA 和 viewport:
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",并在browser.new_context()中传入viewport和user_agent - 避免快速连续访问:加
await asyncio.sleep(0.3)在截图之间(不是固定延时,可用指数退避)
如何稳定保存高清截图并处理失败?
page.screenshot() 默认是 PNG、视口尺寸,不包含滚动内容,且超时默认 30 秒——这在弱网或动态渲染页面中极易失败。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- 截全图用
full_page=True,但会极大增加内存;更稳的方式是先await page.evaluate("window.scrollTo(0, document.body.scrollHeight)")再截 - 务必设
timeout=15000(毫秒),并捕获TimeoutError和Error(如导航失败、页面崩溃) - 文件名别用 URL 全路径——含斜杠、问号会报错,用
hashlib.md5(url.encode()).hexdigest()[:8]做前缀 - 失败时保留
page.content()到 .html 文件,方便后续人工排查是不是跳了登录页或验证码
并发量一上去就 OOM 或卡死?检查这三点
Playwright 进程本身不泄漏,但 Python 的 asyncio 事件循环、未关闭的 page、缓存的二进制截图数据会快速吃光内存。
立即学习“Python免费学习笔记(深入)”;
- 每个
page用完必须显式await page.close(),不能只靠 context.close() - 截图结果(bytes)别长期存在变量里,写入磁盘后立即
del img_bytes - 用
asyncio.Semaphore(10)限制最大并发数,比用asyncio.gather()全扔进去安全得多
真正难的不是并发逻辑,而是每个页面加载状态的判断粒度——等 networkidle 太保守,等 domcontentloaded 又太激进。得结合 page.wait_for_function() 检查关键元素是否存在,这个没法偷懒。

















