使用Node.js爬取Nike网站时图片返回Base64的问题求助
问题描述
使用Node.js爬取Nike加拿大官网新品鞋类页面(https://www.nike.com/ca/w/new-shoes-3n82yzy7ok)时,已成功获取商品名称、价格、链接等数据,但图片字段返回的是Base64占位符(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7),而非预期的图片URL。
页面中图片元素示例:
<img alt="Nike Air Max Dn Men's Shoes" class="product-card__hero-image css-1fxh5tw" height="100%" loading="eager" sizes="" src="https://static.nike.com/a/images/c_limit,w_592,f_auto/t_product_v1/f50070d2-77a3-4213-aebf-9371d9759548/air-max-dn-shoes-q51Wwn.png" width="100%">
爬取输出示例:
[ Scraped Shoes: { name: 'Nike Air Max Dn', price: '$210', color: "Men's Shoes", image: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7', href: 'https://www.nike.com/ca/t/air-max-dn-shoes-q51Wwn/DV3337-008' }, ... ]
当前使用的爬取代码:
async function scrapeShoes(url) { try { const response = await axios.get(url); if (response.status === 200) { const html = response.data; const $ = cheerio.load(html); const shoes = []; $('.product-card').each((index, element) => { const name = $(element).find('.product-card__title').text().trim(); const price = $(element).find('.product-price').text().trim(); const color = $(element).find('.product-card__subtitle').text().trim(); let image = $(element).find('.product-card__hero-image').attr('src'); const href = $(element).find('.product-card__link-overlay').attr('href'); const shoe = { name, price, color, image, href }; shoes.push(shoe); }); console.log('Scraped Shoes:', shoes); return shoes; } else { throw new Error(`Failed to retrieve data. Status code: ${response.status}`); } } catch (error) { throw new Error('Error fetching data:', error); } } const targetUrl = 'https://www.nike.com/ca/w/new-shoes-3n82yzy7ok'; scrapeShoes(targetUrl) .then(() => { }) .catch(error => { console.error('Error scraping website:', error); });
问题原因
Nike官网采用动态渲染/懒加载机制:初始HTML中图片的src属性填充的是Base64占位图,真实图片URL存储在data-src、data-lazy-src这类自定义属性中,页面加载完成后由JavaScript替换为实际URL。而Cheerio只能解析初始HTML,无法执行页面中的JavaScript,因此获取到的是占位图的Base64值。
解决方案
方案1:获取真实图片的自定义属性
检查图片元素的其他属性,修改代码中图片的获取逻辑,优先读取存储真实URL的属性:
// 替换原image获取行,依次尝试不同属性,兜底用原src let image = $(element).find('.product-card__hero-image').attr('data-src') || $(element).find('.product-card__hero-image').attr('data-lazy-src') || $(element).find('.product-card__hero-image').attr('src');
方案2:使用支持JS渲染的爬虫工具
如果方案1无效,说明页面完全依赖JavaScript渲染数据,此时需要用Puppeteer或Playwright这类模拟浏览器的工具,执行页面JS后再获取数据。
示例(Puppeteer):
const puppeteer = require('puppeteer'); async function scrapeShoesWithPuppeteer(url) { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto(url, { waitUntil: 'networkidle2' }); // 等待页面加载稳定 const shoes = await page.evaluate(() => { const shoeElements = document.querySelectorAll('.product-card'); return Array.from(shoeElements).map(el => ({ name: el.querySelector('.product-card__title').textContent.trim(), price: el.querySelector('.product-price').textContent.trim(), color: el.querySelector('.product-card__subtitle').textContent.trim(), image: el.querySelector('.product-card__hero-image').src, href: el.querySelector('.product-card__link-overlay').href })); }); console.log('Scraped Shoes:', shoes); await browser.close(); return shoes; } scrapeShoesWithPuppeteer('https://www.nike.com/ca/w/new-shoes-3n82yzy7ok') .catch(error => console.error('Error:', error));
方案3:直接调用Nike内部API
Nike官网的商品数据通常来自内部API,可通过浏览器开发者工具的Network面板,查找加载商品列表的AJAX请求(搜索products类关键词),直接调用该API获取JSON格式数据,这种方式更稳定高效,返回的结果中会包含完整的图片URL。
内容的提问来源于stack exchange,提问作者Tafadzwa Marisa

