Pyppeteer无头模式启动失败、空白页或超时,主因是新headless模式兼容性差、自动化特征暴露、沙箱冲突及JS渲染时机不当;需降级为headless="old"、注入JS隐藏webdriver、配置--no-sandbox等参数,并用networkidle2等待和evaluateOnNewDocument补丁。

Pyppeteer 默认就是无界面渲染的,但很多人卡在启动失败、空白页、超时或被识别上——核心问题不是“怎么开无头”,而是“怎么让无头环境真正可用”。
为什么 headless=True 启动后页面空白或加载超时?
Pyppeteer 0.4+ 版本默认启用 Chromium 的新 headless 模式(headless=new),它不支持某些 DOM API(如 window.chrome)且对 navigator 属性更敏感,导致部分网站直接拒绝渲染或 JS 报错。
- 显式降级到旧模式:
headless="old"(推荐用于兼容性要求高的场景) - 禁用自动化特征:必须加
--disable-blink-features=AutomationControlled - 隐藏
headless痕迹:设置user-agent并覆盖navigator.webdriver - 避免沙箱冲突(Linux 常见):加上
--no-sandbox和--disable-setuid-sandbox
启动示例:
browser = await launch(
headless="old",
args=[
"--no-sandbox",
"--disable-setuid-sandbox",
"--disable-blink-features=AutomationControlled",
"--disable-infobars",
],
ignoreHTTPSErrors=True,
)如何绕过网站对无头浏览器的检测?
多数反爬通过 navigator.webdriver、chrome 对象、permissions 或字体指纹识别 Pyppeteer。仅靠参数不够,需注入 JS 补丁。
立即学习“Python免费学习笔记(深入)”;
- 在页面加载前执行覆盖脚本:
page.evaluateOnNewDocument() - 必须清除
webdriver属性并伪造chrome对象 - 补全缺失的
PermissionsAPI(否则某些站点 JS 报错中断) - 慎用
--disable-dev-shm-usage:虽能解决内存问题,但会暴露低性能特征
关键 JS 注入片段:
await page.evaluateOnNewDocument("""
Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
window.chrome = { runtime: {} };
Object.defineProperty(navigator, 'plugins', {
get: () => [1, 2, 3, 4, 5],
});
""")
page.goto() 卡住或返回空内容怎么办?
不是网络问题,而是无头环境下资源加载策略不同:默认不加载图片、字体、第三方 iframe,且 JS 执行时机不可靠。
- 强制等待完整加载:
waitUntil="networkidle2"(比"load"更稳妥) - 禁用图片节省资源但可能影响渲染:
page.setExtraHTTPHeaders({"Accept": "text/html"})+ 关闭图片加载 - 手动触发关键 JS:用
page.waitForFunction()等待某个变量就绪,而非依赖 DOM 出现 - 捕获真实错误:
page.on("error", print)和page.on("pageerror", print)必须监听
推荐 goto 写法:
await page.goto(url, {
waitUntil: "networkidle2",
timeout: 30000,
})Pyppeteer 在 Linux 服务器上启动失败的常见原因
报错如 chromium failed to start、No such file or directory 或 segfault,基本都和 Chromium 二进制路径或依赖缺失有关。
- 不要依赖 pip 自带的 Chromium:用
pyppeteer-install命令重新下载(它会校验完整性) - 确认系统有字体库:
apt install fonts-liberation libxss1 libappindicator1(Ubuntu/Debian) - 检查磁盘空间:Chromium 解压后约 200MB,
/tmp不足会导致静默失败 - 容器环境(Docker)必须加
--shm-size=2g,否则 shared memory 不足直接崩溃
验证是否真启动成功:
print(await browser.version()) # 应输出类似 "Chrome/116.0.5845.96"
无界面抓取最难的从来不是启动,而是让目标网站“相信你是个真人”。参数只是起点,JS 补丁、加载策略、错误捕获三者缺一不可;漏掉任意一个,都可能在某个特定页面突然失效。


















