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

使用Node Crawler完成爬取无新链接时,如何触发结果输出代码?

解决爬虫完成后执行后续操作的问题

你的核心问题是当前代码用setTimeout延迟添加爬取任务,导致爬虫队列无法追踪所有待处理任务,drain事件会提前触发,没法在真正爬完所有链接后执行存文件等操作。另外async/await的使用没发挥作用,因为crawlAllUrls没有返回Promise。

下面是修改后的代码,解决这些问题并实现你要的功能:

const Crawler = require("crawler");
const fs = require("fs").promises; // 用Promise版fs方便异步写入

// 改用Set存储已爬链接,查找效率比数组高
const crawledUrls = new Set();
const baseUrl = 'http://www.five12.co.uk/';

// 初始化爬虫,配置爬取间隔(替代你原来的setTimeout)
const c = new Crawler({
  rateLimit: 5000, // 每5秒爬一个,和你原来的延迟一致
  callback: handleCrawlResult
});

function handleCrawlResult(err, res, done) {
  if (err) {
    console.error(`爬取${res.options.uri}失败:`, err);
    return done();
  }

  const $ = res.$;
  try {
    $("a").each((_, element) => {
      let href = $(element).attr('href');
      if (!href) return;

      // 解析相对路径,转换成完整URL
      const fullUrl = new URL(href, baseUrl).href;
      // 只处理当前域名的内部链接,且未爬过的
      if (fullUrl.startsWith(baseUrl) && !crawledUrls.has(fullUrl)) {
        crawledUrls.add(fullUrl);
        console.log(`发现新链接: ${fullUrl}`);
        // 直接加入爬虫队列,由rateLimit控制速度
        c.queue(fullUrl);
      }
    });
  } catch (e) {
    console.error(`处理${res.options.uri}时出错:`, e);
  }
  done();
}

// 所有任务完成时触发drain事件,在这里执行后续操作
c.on('drain', async function() {
  console.log("\n爬取完成!所有内部链接如下:");
  const allUrls = Array.from(crawledUrls);
  allUrls.forEach(url => console.log(url));

  // 写入文本文件
  try {
    await fs.writeFile('爬取结果.txt', allUrls.join('\n'));
    console.log("结果已写入爬取结果.txt");
  } catch (writeErr) {
    console.error("写入文件失败:", writeErr);
  }

  // 如果要写入Google表格,可以用对应的npm包,思路是:
  // 1. 安装对应包
  // 2. 配置Google API权限
  // 3. 在drain事件中调用API将allUrls写入表格
});

// 启动爬虫
c.queue(baseUrl);

关键修改说明:

  • 用Set存储已爬链接:Set的has方法时间复杂度是O(1),比数组includes的O(n)高效得多,爬大量链接时差距明显。
  • 用爬虫自带的rateLimit:直接在初始化爬虫时配置rateLimit,不用自己写setTimeout,爬虫会自动控制任务间隔,且所有任务都在队列管理中,drain事件会在所有任务完成后正确触发。
  • 正确解析URL:用URL类处理相对路径,避免手动拼接出错,比如处理/page这类相对路径时,会自动转换成完整的http://www.five12.co.uk/page。
  • 异步写入文件:用fs.promises的writeFile,配合async/await处理文件写入的异步操作,避免回调嵌套。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 18:18:27