Axios+Cheerio爬取同主题多站点报object is not iterable错误
问题修复说明
你的代码存在两个核心问题,对应修复点如下:
object is not iterable报错原因:axios.all()返回的是包含多个响应对象的数组,而非单个响应,你直接读取response.data得到的是undefined,Cheerio加载无效内容时就会触发迭代错误。此外你把Axios请求定义在路由外层,服务启动时就会发起请求,后续接口调用拿到的是首次请求的缓存结果,不会实时更新。- 双站点解析逻辑错误:两个站点的HTML内容是独立返回的,不能合并成一个Cheerio实例加载解析。同时全局定义的
mice数组会在多次接口调用时重复累加数据,需要定义在路由处理函数内部;爬取结果建议增加来源字段,区分不同站点的爬取内容。
可直接运行的修复代码
const PORT = 5000; import express from "express"; import axios from "axios"; import cheerio from "cheerio"; const app = express(); const tomsHardware = "https://www.tomshardware.com/best-picks/best-gaming-mouse"; const pcGamer = "https://www.pcgamer.com/the-best-gaming-mouse/"; app.get('/', (req, res) => { res.json('Welcome to my gaming mouse crawler API!'); }); app.get('/mouse', async (req, res) => { // 数组定义在路由内,避免多次请求数据累加 const mice = []; try { // 并发发起两个站点请求,拆分两个独立响应 const [tomsRes, pcGamerRes] = await axios.all([ axios.get(tomsHardware), axios.get(pcGamer) ]); // 单独解析Tom's Hardware页面 const $toms = cheerio.load(tomsRes.data); $toms('.product__title').each(function () { const title = $toms(this).text().trim(); mice.push({ title, source: "Tom's Hardware" }); }); // 单独解析PC Gamer页面 const $pc = cheerio.load(pcGamerRes.data); $pc('.product__title').each(function () { const title = $pc(this).text().trim(); mice.push({ title, source: "PC Gamer" }); }); res.json(mice); } catch (err) { console.log(err); res.status(500).json({msg: 'crawl failed', error: err.message}); } }); app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); });
补充说明:如果后续两个站点的
.product__title选择器匹配到无关内容,可以针对每个站点单独调整选择器规则,不会互相影响。
内容的提问来源于stack exchange,提问作者A.bashary
相关产品推荐
相关产品推荐

