You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 18:57:51