Node.js下Puppeteer爬取函数仅返回单个商品链接问题排查
问题根因
你只拿到1个商品链接不是逻辑问题,核心是DOM选择器写错了:
你写的选择器section > div.coleccion-prods > div > div.vitrine.resultItemsWrapper匹配的是整个商品列表的外层大容器,整个搜索结果页就1个这个节点,所以$$eval拿到的links数组长度本身就是1,当然只能返回第一个商品的链接。
另外现有代码还有几个会导致拿不全结果、甚至运行报错的隐患:
- 等待条件不对:只等
.wrapper > .main加载时,商品列表还没完成渲染,甚至可能连第一个商品节点都没稳定挂载 - 站点商品用了滚动懒加载:不滚动到页面底部的话,后面的商品根本不会渲染到DOM里,就算选对选择器也拿不全
- 过滤逻辑写反:搜索关键词是pepsi,现有过滤规则是把品牌文本等于"PEPSI"的商品全部排除,最后只会剩下非百事的商品链接
- 没有空值兜底:只要有一个商品节点里缺
.marca或者h3>a节点,整个提取逻辑会直接抛错中断
修复方案
- 把
$$eval的选择器改成单个商品项对应的选择器,该站点单个商品节点的选择器为.vitrine.resultItemsWrapper .product-item - 调整等待逻辑,直接等待商品项节点渲染完成,页面跳转时加
networkidle2配置等待网络请求空闲 - 增加自动滚动逻辑,触发页面懒加载,等所有商品渲染完成后再提取链接
- 修正过滤逻辑,同时给DOM查询加空值判断,避免个别商品节点结构异常导致整体报错
修复后的可运行代码:
const scraperObject = { url: 'https://diaonline.supermercadosdia.com.ar/busca/?ft=pepsi', async scraper(browser){ let page = await browser.newPage(); console.log(`Navigating to ${this.url}...`); // 等待网络基本空闲再继续 await page.goto(this.url, { waitUntil: 'networkidle2' }); // 等待商品项挂载 await page.waitForSelector('.product-item'); // 自动滚动到底部,触发所有懒加载商品 await page.evaluate(async () => { await new Promise((resolve) => { let totalHeight = 0; const scrollStep = 300; const timer = setInterval(() => { const pageTotalHeight = document.body.scrollHeight; window.scrollBy(0, scrollStep); totalHeight += scrollStep; if(totalHeight >= pageTotalHeight){ clearInterval(timer); resolve(); } }, 100); }); }); // 等最后一批商品渲染完成 await page.waitForTimeout(1500); // 提取所有符合要求的商品链接 let urls = await page.$$eval('.vitrine.resultItemsWrapper .product-item', items => { // 过滤品牌为PEPSI的商品,空节点直接排除 const validItems = items.filter(item => { const brandEl = item.querySelector('.marca'); return brandEl && brandEl.textContent.trim() === "PEPSI" }) // 提取有效链接 return validItems.map(el => { const linkEl = el.querySelector('h3 > a'); return linkEl ? linkEl.href : null }).filter(Boolean); }); console.log(urls); } } module.exports = scraperObject;
注意:如果需要翻页爬取全量结果,可以在提取完当前页链接后,自动点击下一页按钮重复上述滚动、提取逻辑即可。
内容的提问来源于stack exchange,提问作者Tomas Iniguez
相关产品推荐
相关产品推荐

