用Cheerio爬取Carrefour UAE商品返回空数组,如何解决?
问题:爬取家乐福阿联酋网站商品数据返回空数组
我尝试了以下代码来获取商品标题和价格数组,但返回空数组:
const cheerio = require("cheerio"); const axios = require('axios'); async function getProducts() { try{ const res = await axios.get('https://www.carrefouruae.com/mafuae/en/v4/search?keyword=tomato%20kathcup'); const html = await res.data; const $ = cheerio.load(html); const products = []; $('ul[data-testid]').each((i, el) => { const title = $(el).find('a[data-testid="product_name"]').text().trim(); const price = $(el).find('div[data-testid="product_price"] .css-fzp91j').text().trim(); products.push({ title, price }); }); console.log(products); }catch(err){ console.log(err) } }; getProducts();
目标链接为 https://www.carrefouruae.com/mafuae/en/v4/search?keyword=tomato%20kathcup,用相同方式爬取亚马逊正常,但爬取家乐福网站失败,请问该如何修改?
原因分析
家乐福阿联酋网站采用客户端动态渲染:axios直接请求返回的HTML仅包含页面骨架,商品数据是页面加载完成后通过AJAX请求从后端接口获取的,因此cheerio无法从静态HTML中解析到商品信息。而亚马逊部分页面采用服务端渲染,静态HTML中直接包含商品数据,所以之前的方法可以生效。
解决方法
方法1:用无头浏览器(Puppeteer)模拟页面完整加载
通过Puppeteer启动无头浏览器,等待页面渲染完成后再解析DOM:
- 先安装依赖:
npm install puppeteer
- 修改后的代码:
const puppeteer = require('puppeteer'); async function getProducts() { let browser; try { browser = await puppeteer.launch({ headless: 'new' }); const page = await browser.newPage(); await page.goto('https://www.carrefouruae.com/mafuae/en/v4/search?keyword=tomato%20kathcup', { waitUntil: 'networkidle2' }); // 等待商品列表元素加载完成 await page.waitForSelector('ul[data-testid] li[data-testid="product_item"]'); const products = await page.evaluate(() => { const items = document.querySelectorAll('ul[data-testid] li[data-testid="product_item"]'); return Array.from(items).map(item => { const title = item.querySelector('a[data-testid="product_name"]').textContent.trim(); const price = item.querySelector('div[data-testid="product_price"] .css-fzp91j').textContent.trim(); return { title, price }; }); }); console.log(products); } catch (err) { console.error(err); } finally { if (browser) await browser.close(); } } getProducts();
方法2:直接调用后端API接口
通过浏览器开发者工具抓包,可获取商品数据的真实API接口,直接请求接口获取JSON数据,效率更高:
const axios = require('axios'); async function getProducts() { try { const res = await axios.get('https://www.carrefouruae.com/api/v1/products/search', { params: { keyword: 'tomato kathcup', storeId: '10001', page: 1, size: 20 }, headers: { 'Accept': 'application/json', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36' } }); const products = res.data.data.map(item => ({ title: item.name, price: item.price.current.value })); console.log(products); } catch (err) { console.error(err); } } getProducts();
注意事项
- 方法2中的API参数(如
storeId)可能随网站更新变化,建议通过浏览器抓包确认最新参数; - 频繁请求可能触发反爬机制,建议添加请求间隔或使用代理;
- 遵守网站
robots.txt协议和使用条款,避免违规爬取。
内容的提问来源于stack exchange,提问作者Mahinur Rahman
相关产品推荐
相关产品推荐

