Pyppeteer翻页比requests慢因启动Chromium并加载全部资源,默认等待networkidle0;应改用domcontentloaded、禁用图片CSS、清缓存;需复用browser实例避免重复初始化;提取翻页元素要等渲染、检查可见性、监听AJAX;并发需限流防Target closed。

Pyppeteer翻页为什么比requests慢得多
Pyppeteer本质是启动Chromium实例,每次page.goto()都触发完整页面加载(HTML + JS + CSS + 图片),而requests只拿HTML文本。哪怕只是翻页,Pyppeteer默认会等networkidle0(所有网络请求结束),遇到广告、埋点JS、第三方统计脚本就会卡住几秒。
实操建议:
- 用
waitUntil: 'domcontentloaded'替代默认的networkidle0,跳过资源加载等待 - 禁用图片和CSS:
page.setExtraHTTPHeaders({'Accept': 'text/html'})配合拦截请求 - 翻页前手动清空
page._client缓存(Pyppeteer 1.0+不自动清理)
如何避免Pyppeteer翻页时重复初始化浏览器
很多人在循环里写browser = await launch()再page = await browser.newPage(),结果每页都新建浏览器进程——内存暴涨、启动延迟高、IP暴露风险上升。
正确做法是复用单个browser实例:
- 在循环外调用
launch(),传入headless=True和args=['--no-sandbox', '--disable-setuid-sandbox'] - 每页用
await browser.newPage(),用完立即await page.close()(不关browser) - 若需保持登录态,把
page设为全局或传入函数,避免重复page.goto(login_url)
示例关键片段:
browser = await launch(headless=True, args=[...])<br>for url in urls:<br> page = await browser.newPage()<br> await page.goto(url, waitUntil='domcontentloaded')<br> # 抓取逻辑<br> await page.close() # 关页面,不关浏览器
翻页链接提取失败的三个高频原因
Pyppeteer执行JS后DOM已渲染,但page.querySelectorAll()仍拿不到翻页元素,常见于:
- 分页按钮是JS动态插入的,需先
await page.waitForSelector('.next-page')再查 - 翻页元素被
display: none或visibility: hidden遮盖,加visible=True参数:await page.waitForSelector('.pager a', visible=True) - 页面用
history.pushState做无刷新翻页,此时page.url不变,需监听response事件捕获AJAX返回的JSON数据
并发翻页时Pyppeteer报Target closed怎么处理
并发开多个page没问题,但若共用同一browser且未控制并发数,Chromium会因内存超限主动杀掉page,抛出Target closed错误。
解决路径很直接:
- 用
asyncio.Semaphore(3)限制同时活跃page数(3是经验值,视内存调整) - 每个任务加
try/except捕获pyppeteer.errors.NetworkError和pyppeteer.errors.PageError - 失败后不要立刻重试,加
await asyncio.sleep(1)再page = await browser.newPage()重建
真实场景中,翻页效率瓶颈往往不在代码本身,而在目标站反爬策略响应时间——比如每页强制sleep(2)比优化Pyppeteer参数更有效。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











