BigBasket商品爬取失败求助:重定向循环与监听器溢出警告
解决Bigbasket爬取时的重定向循环与事件监听器泄漏问题
看起来你在爬取Bigbasket搜索结果时遇到了两个典型的爬虫问题:重定向循环和事件监听器泄漏警告。我来帮你逐个解决:
一、先处理「Exceeded maxRedirects」重定向循环问题
这个错误说明Bigbasket的服务器一直在把你的请求重定向,大概率是因为网站检测到你的请求来自爬虫,而非真实浏览器。解决思路是让你的请求更像真实用户的浏览器请求:
- 完善请求头信息:你现在只设置了
user-agent,但真实浏览器会发送更多请求头。建议添加Accept、Accept-Language、Referer等字段,模拟正常的浏览行为。 - 启用Cookie会话:很多电商网站会用Cookie来识别合法会话,你需要启用Cookie Jar来保存请求过程中的Cookie,避免被判定为陌生请求。
- 修复硬编码的搜索词:你的代码里定义了
searchQuery但最后用了硬编码的tata,应该动态替换成用户传入的搜索词,避免不必要的重复请求。 - 限制重定向次数:手动设置合理的重定向上限,防止无限循环。
二、解决「MaxListenersExceededWarning」事件监听器泄漏
这个警告是因为request模块的EventEmitter实例添加了过多监听器,通常是全局设置监听器上限的方式不对,或者请求实例没有被正确清理:
- 针对单个请求设置监听器上限:不要全局修改
process.setMaxListeners,应该给每个请求实例单独设置,避免影响其他进程。 - 考虑迁移到现代HTTP客户端:
request模块已经被官方弃用了,推荐使用axios或node-fetch,它们的事件管理更完善,不容易出现这类警告。
修改后的完整代码(基于request模块)
const request = require('request'); const cheerio = require('cheerio'); exports.getBBPrices = (req, res, next) => { let searchQuery = req.query.search; // 先检查搜索词是否存在 if (!searchQuery) { return res.status(400).send('请提供搜索关键词'); } searchQuery = searchQuery.split(' ').join('+'); console.log('搜索词:', searchQuery); const options = { headers: { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.5', 'Referer': 'https://www.bigbasket.com/', 'DNT': '1' // 表示不跟踪请求 }, method: 'GET', followRedirect: true, maxRedirects: 5, // 限制最多5次重定向,避免循环 jar: true // 启用Cookie Jar,自动保存和发送Cookie }; // 动态生成搜索URL,不再硬编码tata const url = `https://www.bigbasket.com/ps/?q=${searchQuery}`; const result = []; // 创建请求实例并单独设置监听器上限 const reqInstance = request(url, options, function(err, response, html){ if(!err) { const $ = cheerio.load(html); // 这里写你的后续解析逻辑,比如提取商品信息 // 示例:$('div.product').each((i, el) => { ... }) res.status(200).json(result); } else { console.log('请求错误:', err); res.status(500).send('获取数据失败'); } }); // 给当前请求实例设置监听器上限,而非全局 reqInstance.setMaxListeners(10); };
更推荐的方案:改用axios模块
因为request已弃用,这里提供一个基于axios的版本,代码更简洁,也更少出现事件监听器问题:
const axios = require('axios'); const cheerio = require('cheerio'); exports.getBBPrices = async (req, res, next) => { try { let searchQuery = req.query.search; if (!searchQuery) { return res.status(400).send('请提供搜索关键词'); } searchQuery = searchQuery.split(' ').join('+'); // 发送GET请求 const response = await axios.get(`https://www.bigbasket.com/ps/?q=${searchQuery}`, { headers: { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.5', 'Referer': 'https://www.bigbasket.com/', 'DNT': '1' }, maxRedirects: 5, withCredentials: true // 自动处理Cookie }); const $ = cheerio.load(response.data); // 后续解析逻辑 const result = []; // 示例:$('div.product-tuple').each((i, el) => { ... }) res.status(200).json(result); } catch (err) { console.log('请求错误:', err); res.status(500).send('获取数据失败'); } };
额外提醒
Bigbasket有严格的反爬机制,如果你频繁请求,可能会被封禁IP。建议:
- 添加请求延迟,比如每次请求间隔1-2秒;
- 必要时使用代理IP池轮换IP;
- 不要一次性爬取大量数据,分批次处理。
内容的提问来源于stack exchange,提问作者Rahul Shaw
相关产品推荐
相关产品推荐

