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

使用Fetch与Cheerio爬取ostrovok.ru网站返回空结果问题

问题分析与修复方案

你的代码输出空数组主要有以下几个关键问题:

核心问题点

  • 空选择器导致无数据提取:$("")是无效选择器,自然无法获取任何元素,chunk始终为空数组。
  • 分页逻辑完全错误:你用来获取下一页URL的选择器指向的是酒店标题的<a>标签,而且attr("TEXT")是错误用法(应该用text()或attr("href")),导致url很快变为undefined,后续请求失效。
  • 缺少请求头被反爬拦截:直接用fetch请求可能被网站识别为爬虫,返回空内容或错误状态码。
  • 未实现目标数据提取逻辑:代码里没有编写提取酒店名称、价格、评分的逻辑。

修复后的代码

const cheerio = require("cheerio");
let fs = require('fs').promises; // 使用promise版本适配async/await
const base = "https://ostrovok.ru/hotel/russia/adler/";

// 模拟浏览器请求头,避免被反爬拦截
const fetchOptions = {
  headers: {
    "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 delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

(async () => {
  let currentPage = 1;
  const data = [];
  const maxPages = 5; // 先测试少量页面,避免请求过多被封

  while (currentPage <= maxPages) {
    try {
      const url = `${base}?page=${currentPage}`;
      console.log(`正在爬取第${currentPage}页: ${url}`);
      
      const res = await fetch(url, fetchOptions);
      if (!res.ok) {
        console.log(`请求失败,状态码: ${res.status}`);
        break;
      }

      const html = await res.text();
      const $ = cheerio.load(html);

      // 遍历所有酒店卡片,提取目标数据
      $(".HotelCard_root__r0TF9").each((_, el) => {
        const $card = $(el);
        const hotelName = $card.find(".HotelCard_name__2Wid6").text().trim();
        const price = $card.find(".PriceInfo_price__3b9i2").text().trim();
        const rating = $card.find(".Rating_value__1S13c").text().trim();

        if (hotelName) { // 确保有有效数据才加入数组
          data.push({
            hotelName,
            price,
            rating
          });
        }
      });

      // 检查是否存在下一页
      const hasNextPage = !!$(".Pagination_next__3Z8fQ").length;
      if (!hasNextPage) break;

      currentPage++;
      await delay(1000); // 每页间隔1秒,降低被封风险
    } catch (err) {
      console.error(`爬取第${currentPage}页出错:`, err);
      break;
    }
  }

  console.log("爬取结果:", JSON.stringify(data, null, 2));
  await fs.writeFile('hotels.json', JSON.stringify(data, null, 2));
  console.log("数据已保存到hotels.json");
})();

关键修复说明

  1. 添加请求头:通过User-Agent模拟浏览器请求,避免被网站直接拦截。
  2. 正确的选择器:使用.HotelCard_root__r0TF9定位酒店卡片,再从卡片内提取名称、价格、评分的具体元素(若网站DOM更新,需重新调整选择器)。
  3. 合理分页逻辑:通过页码递增请求,同时检查下一页按钮状态,避免无效循环。
  4. 请求延迟:添加delay函数控制请求频率,降低被反爬机制封禁的概率。
  5. 使用Promise版fs:避免回调嵌套,适配async/await语法。

注意事项

  • 网站DOM结构可能随时更新,若后续爬取失效,需重新检查页面元素的类名或选择器。
  • 不要设置过高的maxPages或过短的请求间隔,避免对目标网站造成服务器压力,同时防止IP被封禁。

内容的提问来源于stack exchange,提问作者N9ter

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 21:22:33