如何修改Node.js爬虫代码实现仅抓取可视商品信息?
解决方案
要实现仅抓取可视区域内的商品,核心是在浏览器上下文里判断元素是否处于可视范围,同时修正原代码的滚动与数据抓取逻辑,以下是修改后的完整代码:
const puppeteer = require('puppeteer'); // 存储已抓取的商品标题,避免重复打印 const scrapedTitles = new Set(); (async () => { const browser = await puppeteer.launch({ headless: false }); const page = await browser.newPage(); // 设置视口大小,模拟真实浏览器可视区域 await page.setViewport({ width: 1200, height: 800 }); await page.goto('https://www.balenciaga.com/en-us/women/shoes/sneakers', { waitUntil: 'networkidle2' }); // 先抓取初始可视区域的商品 await getVisibleData(page); // 开始滚动加载并抓取 await scrollAndScrape(page); })(); // 滚动页面并等待新内容加载 const scrollAndScrape = async (page) => { let previousHeight = await page.evaluate('document.body.scrollHeight'); while (true) { // 滚动到页面底部 await page.evaluate('window.scrollTo(0, document.body.scrollHeight)'); // 等待新内容加载(可根据页面加载速度调整时间) await page.waitForTimeout(2000); // 抓取当前可视区域的商品 await getVisibleData(page); // 检查是否已经滚动到页面底部 const currentHeight = await page.evaluate('document.body.scrollHeight'); if (currentHeight === previousHeight) { console.log('已滚动到页面底部,停止抓取'); break; } previousHeight = currentHeight; } }; // 抓取当前可视区域内的商品 const getVisibleData = async (page) => { const visibleProducts = await page.evaluate(() => { // 判断元素是否在可视区域内的工具函数 const isElementVisible = (el) => { const rect = el.getBoundingClientRect(); return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth) ); }; const products = []; // 获取所有商品元素 const items = document.querySelectorAll('.l-productgrid__item .c-product__infos'); items.forEach(item => { if (isElementVisible(item)) { const title = item.querySelector('h2').textContent.trim(); const price = item.querySelector('p').textContent.trim(); products.push({ title, price }); } }); return products; }); // 过滤已抓取过的商品,避免重复打印 const newProducts = visibleProducts.filter(p => !scrapedTitles.has(p.title)); // 打印新抓取的商品 newProducts.forEach((res, i) => { scrapedTitles.add(res.title); console.log(`${scrapedTitles.size} 名稱: ${res.title}, 價錢: ${res.price}`); }); };
关键修改点说明
- 移除Cheerio依赖:Cheerio基于静态DOM解析,无法判断元素是否在可视区域,直接在
page.evaluate中操作浏览器上下文的DOM,才能准确判断可视性。 - 可视区域判断函数:通过
getBoundingClientRect()获取元素的位置信息,对比浏览器视口的宽高,判断元素是否完全处于可视范围内(也可根据需求调整为部分可见即抓取)。 - 滚动逻辑优化:使用循环滚动替代递归调用,添加滚动终止条件(当页面高度不再变化时,说明已到底部),避免无限递归。
- 去重处理:用
Set存储已抓取的商品标题,避免滚动时重复打印之前已抓取过的商品。 - 视口设置:初始化时设置浏览器视口大小,模拟真实用户的可视区域,确保判断逻辑准确。
内容的提问来源于stack exchange,提问作者Caramel
相关产品推荐
相关产品推荐

