如何使用 Puppeteer 稳健实现分页爬取(Next Page)

10次阅读

如何使用 Puppeteer 稳健实现分页爬取(Next Page)

本文详解 puppeteer 分页爬取中常见的 url 重复处理、导航失效及页码错乱问题,提供可落地的解决方案,确保每页仅处理一次,并正确识别末页边界。

在使用 Puppeteer 进行分页爬取(如 https://clerk.house.gov/Votes 这类 前端 分页站点)时,一个典型陷阱是:页面通过哈希跳转(#)或异步 路由 更新 URL,导致 page.waitForNavigation() 无法可靠触发——这正是原代码反复打印 ?page=2#、?page=3# 等重复 URL 的根本原因。waitForNavigation 仅监听完整的导航事件(如 GET 请求),而 SPA 或锚点驱动的分页常不触发该事件。

✅ 正确做法:用 browser.waitForTarget() 监听新页面加载

替代脆弱的 waitForNavigation(),应监听 浏览器 目标(Target)的创建与 URL 变化。关键逻辑如下:

const url = page.url(); console.log('Processing page:', url);  // ✅ 提取当前页码(兼容初始页无参数的情况)const currentPageNum = url.includes('?page=')   ? parseInt(url.match(/page=(d+)/)[1], 10)   : 1;  // ✅ 点击“下一页”按钮(注意:直接 click() 即可,无需 selector 参数)await nextButton.click();  // ✅ 等待目标 URL 变为预期的下一页(更鲁棒,不受 hash 干扰)await browser.waitForTarget(target => target.url().endsWith(`?page=${currentPageNum + 1}`),   {timeout: 10000} );

⚠️ 注意事项:nextButton.click() 不接受 CSS 选择器参数(原代码 click(‘a[aria-label=”Next”]…’) 是错误用法,会报错);必须在点击前获取当前 URL,否则 page.url() 可能仍是旧地址(因点击后 URL 更新有延迟);waitForTarget 需设置合理超时(如 10s),避免无限等待;初始页(/Votes)无 ?page= 参数,需显式判断并设为 page=1,否则后续页码计算错误。

✅ 补充:处理末页边界(防止漏掉最后一页)

原逻辑在「下一页按钮消失时退出」,意味着 最后一页的数据从未被提取 。修正方式是: 先处理当前页,再尝试翻页。完整结构建议如下:

while (true) {// ✅ 1. 先处理当前页(无论是否为末页)console.log('Processing page:', page.url());   // ? 在此处插入你的数据提取逻辑,例如:// const votes = await page.$$eval('.vote-item', els => els.map(e => e.textContent));    // ✅ 2. 尝试查找并点击下一页按钮   const nextButton = await page     .waitForSelector('a[aria-label="Next"] span[class~="fa"]', {timeout: 3000})     .catch(() => null);    if (!nextButton) {console.log('No more pages. Scraping completed.');     break;   }    // ✅ 3. 执行翻页(使用上述 waitForTarget 方案)const currentUrl = page.url();   const pageNum = currentUrl.includes('?page=')     ? parseInt(currentUrl.match(/page=(d+)/)[1], 10)     : 1;    await nextButton.click();   await browser.waitForTarget(     t => t.url().endsWith(`?page=${pageNum + 1}`),     {timeout: 10000}   ); }

✅ 总结

  • ❌ 避免 page.waitForNavigation() 处理哈希 /SPA 分页;
  • ✅ 使用 browser.waitForTarget() + URL 断言,精准等待目标页加载;
  • ✅ 始终先处理当前页,再判断是否翻页,确保末页不遗漏;
  • ✅ 点击操作后立即捕获 page.url(),避免页码解析错误;
  • ? 调试时可添加 await page.screenshot({path:page-${pageNum}.png}); 辅助验证页面状态。

遵循以上模式,即可构建稳定、可维护的 Puppeteer 分页 爬虫

星耀云
版权声明:本站原创文章,由 星耀云 2025-12-28发表,共计1905字。
转载说明:转载本网站任何内容,请按照转载方式正确书写本站原文地址。本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。
text=ZqhQzanResources