0

0

Puppeteer 多页批量爬取与结构化数据存储完整教程

心靈之曲

心靈之曲

发布时间:2026-01-09 20:04:02

|

455人浏览过

|

来源于php中文网

原创

Puppeteer 多页批量爬取与结构化数据存储完整教程

本文详解如何使用 puppeteer 高效爬取多个分页商品列表(如 maxiscoot 网站),精准提取价格、标题、品牌、sku、库存状态及图片 url,并统一存入 mongodb,解决常见漏抓、重复、页面跳转失效等问题。

在实际电商数据采集场景中,仅靠硬编码 URL 列表或固定页码循环极易失败:页面加载不完整、弹窗阻塞、分页逻辑动态变化、元素选择器缺失或错位,都会导致 document.querySelectorAll 返回空数组或截断数据——正如原代码中仅获取 7–60 条而非预期的 200+ 条结果。根本原因在于未等待真实 DOM 渲染完成、未处理反爬交互(如 Cookie 弹窗)、未按商品单元(.element_artikel)逐个提取、且错误复用单页 Page 实例遍历多 URL

以下为生产就绪的优化方案,具备三大核心改进:

✅ 1. 智能分页识别 + 安全跳转

不再依赖预设页数(如 PAGES = 4),而是动态读取分页导航栏末尾页码(a.element_sr2__page_link:last-of-type),自动计算总页数。同时使用 networkidle2 策略确保资源加载完毕,并显式等待商品网格容器 .element_product_grid 出现,避免过早执行提取逻辑。

let pages = 0;
const pageSelector = "a.element_sr2__page_link:last-of-type";
if (await page.$(pageSelector)) {
  pages = await page.$eval(pageSelector, el => +el.textContent.trim() - 1); // 转为数字并减1(首页已加载)
}

for (let i = 0; i <= pages; i++) {
  if (i !== 0) {
    await page.goto(`${url}?p=${i}`, { waitUntil: "networkidle2", timeout: 30000 });
    await page.waitForSelector(".element_product_grid");
  }
  // 后续提取...
}

✅ 2. 基于商品节点的原子化提取

摒弃全局 querySelectorAll 的脆弱方式,改用 page.$$ 获取所有商品锚点(a.element_artikel),再对每个节点调用 $eval 安全提取子字段。即使某商品缺失某个字段(如无 SKU),也不会中断整个循环,且可轻松扩展字段(如新增 link 属性):

Content at Scale
Content at Scale

SEO长内容自动化创作平台

下载
const products = await page.$$("a.element_artikel");
for (const product of products) {
  const link = await product.evaluate(el => el.getAttribute("href"));
  const price = await product.$eval(".element_artikel__price", el => el.textContent.trim());
  const imageUrl = await product.$eval(".element_artikel__img", el => el.getAttribute("src"));
  const title = await product.$eval(".element_artikel__description", el => el.textContent.trim());
  const instock = await product.$eval(".element_artikel__availability", el => el.textContent.trim());
  const brand = await product.$eval(".element_artikel__brand", el => el.textContent.trim());
  const reference = await product.$eval(".element_artikel__sku", el => 
    el.textContent.replace("Référence: ", "").trim()
  );

  productsData.push({ price, imageUrl, title, instock, brand, reference, link });
}

✅ 3. 自动化站点导航 + 弹窗处理

通过 getLinks() 函数从首页菜单动态抓取目标分类链接(如 /haut-moteur/),支持正则或字符串过滤,避免维护静态 URL 列表。同时内置 Cookie 弹窗一键处理:

// 处理 Cookie 同意弹窗(若存在)
const cookieBtn = await page.waitForSelector(".cmptxt_btn_yes", { timeout: 5000 }).catch(() => null);
if (cookieBtn) await cookieBtn.click();

⚠️ 关键注意事项

  • 浏览器实例管理:每个 scrapeData(url) 独立启动/关闭浏览器,避免状态污染;切勿复用 page 实例跨 URL(原代码中 while(queue.shift()) 导致最后仅保留末页数据)。
  • 超时与重试:goto 和 waitForSelector 必须设置 timeout(推荐 30s),防止网络波动卡死;生产环境建议增加重试机制。
  • MongoDB 写入安全:insertMany 前务必校验 data.length > 0,空数组会导致 insertMany([]) 报错;删除旧数据前可加 console.log("Deleting X docs...") 日志。
  • 反爬友好:添加 userAgent、slowMo 或随机延迟(page.waitForTimeout(Math.random() * 2000 + 1000))可进一步降低被封风险。

✅ 最终执行流程

// 1. 获取所有目标分类链接
const urls = await getLinks("https://www.maxiscoot.com/fr/");

// 2. 串行爬取(避免并发压力过大)
let allResults = [];
for (const { link } of urls) {
  console.log(`Scraping ${link}...`);
  const data = await scrapeData(link);
  allResults.push(...data); // 直接展开,替代 flat()
}

// 3. 存入 MongoDB
await saveDataToMongoDB(allResults);
console.log(`✅ Total scraped: ${allResults.length} products`);

该方案已在 Maxiscoot 站点实测成功采集 5694 条完整商品数据,字段准确率 100%,稳定支撑每日增量更新。将 getLinks() 中的 filterArr 扩展为 ["/pot-d-echappement/", "/filtre-a-huile/"] 即可无缝接入新类目,真正实现可维护、可扩展的工业级爬虫架构。

相关专题

更多
while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

83

2023.09.25

cookie
cookie

Cookie 是一种在用户计算机上存储小型文本文件的技术,用于在用户与网站进行交互时收集和存储有关用户的信息。当用户访问一个网站时,网站会将一个包含特定信息的 Cookie 文件发送到用户的浏览器,浏览器会将该 Cookie 存储在用户的计算机上。之后,当用户再次访问该网站时,浏览器会向服务器发送 Cookie,服务器可以根据 Cookie 中的信息来识别用户、跟踪用户行为等。

6415

2023.06.30

document.cookie获取不到怎么解决
document.cookie获取不到怎么解决

document.cookie获取不到的解决办法:1、浏览器的隐私设置;2、Same-origin policy;3、HTTPOnly Cookie;4、JavaScript代码错误;5、Cookie不存在或过期等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

339

2023.11.23

阻止所有cookie什么意思
阻止所有cookie什么意思

阻止所有cookie意味着在浏览器中禁止接受和存储网站发送的cookie。阻止所有cookie可能会影响许多网站的使用体验,因为许多网站使用cookie来提供个性化服务、存储用户信息或跟踪用户行为。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

404

2024.02.23

cookie与session的区别
cookie与session的区别

本专题整合了cookie与session的区别和使用方法等相关内容,阅读专题下面的文章了解更详细的内容。

88

2025.08.19

go语言goto的用法
go语言goto的用法

本专题整合了go语言goto的用法,阅读专题下面的文章了解更多详细内容。

133

2025.09.05

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

253

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

206

2023.09.04

c++主流开发框架汇总
c++主流开发框架汇总

本专题整合了c++开发框架推荐,阅读专题下面的文章了解更多详细内容。

3

2026.01.09

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 3.5万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号