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

基于Nightmare.js的JSON合并需求:生成带递增ID的主JSON

解决方案:基于Nightmare.js的JSON合并与递增ID分配方案

我来给你梳理一个可行的实现方案,刚好之前做过类似的批量抓取合并需求,结合Nightmare.js的特性,咱们可以按以下步骤来完成:

核心思路

咱们的核心目标是持续将新抓取的JSON对象合并到主JSON中,并为新对象分配不重复的递增ID。具体逻辑是:

  1. 持久化存储主JSON(比如本地文件),每次抓取前先读取它;
  2. 找到主JSON中当前最大的ID值;
  3. 用Nightmare.js抓取到新的JSON后,给每个对象替换成从maxID + 1开始的递增ID;
  4. 将处理后的新对象合并到主JSON,再保存回存储介质。

具体实现步骤&代码示例

1. 依赖准备

首先确保你已经安装了Nightmare.js,Node.js内置的fs模块用来处理文件读写:

npm install nightmare

2. 完整代码实现

下面是可直接参考的代码,包含了文件读写、抓取、ID分配和合并逻辑:

const Nightmare = require('nightmare');
const fs = require('fs').promises;
const path = require('path');

// 主JSON文件路径
const MASTER_JSON_PATH = path.join(__dirname, 'master.json');

// 初始化主JSON(如果文件不存在则创建空数组)
async function initMasterJson() {
  try {
    await fs.access(MASTER_JSON_PATH);
  } catch {
    await fs.writeFile(MASTER_JSON_PATH, JSON.stringify([]), 'utf8');
  }
}

// 获取主JSON中的最大ID
async function getMaxId() {
  const masterContent = await fs.readFile(MASTER_JSON_PATH, 'utf8');
  const masterData = JSON.parse(masterContent);
  if (masterData.length === 0) return -1; // 空数组时,第一个ID从0开始
  return Math.max(...masterData.map(item => item.id));
}

// 使用Nightmare.js抓取新的JSON数据
async function fetchNewJson() {
  const nightmare = Nightmare({ show: false }); // show:false 不显示浏览器窗口,生产环境用这个
  try {
    // 这里替换成你的目标页面URL,以及触发XHR请求的操作
    const newJson = await nightmare
      .goto('你的目标页面URL')
      // 模拟变更筛选条件的操作,比如输入框输入、下拉选择等
      .type('#filter-input', '新的筛选条件')
      .click('#submit-filter')
      .wait(2000) // 等待XHR请求完成,根据实际情况调整等待时间
      .evaluate(() => {
        // 这里需要根据实际页面的XHR返回,获取对应的JSON数据
        // 示例:假设页面将XHR响应存在全局变量中
        return window.newFetchedData;
      });
    return newJson;
  } catch (error) {
    console.error('抓取失败:', error);
    return [];
  } finally {
    await nightmare.end();
  }
}

// 合并新数据到主JSON
async function mergeNewData(newData) {
  const maxId = await getMaxId();
  // 为新数据分配递增ID
  const processedNewData = newData.map((item, index) => ({
    ...item,
    id: maxId + 1 + index
  }));
  
  // 读取主JSON并合并
  const masterContent = await fs.readFile(MASTER_JSON_PATH, 'utf8');
  const masterData = JSON.parse(masterContent);
  masterData.push(...processedNewData);
  
  // 保存回主JSON文件
  await fs.writeFile(MASTER_JSON_PATH, JSON.stringify(masterData, null, 2), 'utf8');
  console.log(`成功合并${processedNewData.length}条数据,最新ID为${maxId + processedNewData.length}`);
}

// 定时执行抓取合并任务(比如每10分钟一次,根据你的需求调整间隔)
async function startCrawlingLoop() {
  await initMasterJson();
  setInterval(async () => {
    console.log('开始新一轮抓取...');
    const newData = await fetchNewJson();
    if (newData.length > 0) {
      await mergeNewData(newData);
    } else {
      console.log('本次抓取未获取到有效数据');
    }
  }, 600000); // 10分钟=600000毫秒,可根据实际需求调整
}

// 启动任务
startCrawlingLoop();

3. 关键细节说明

  • 筛选条件变更:在fetchNewJson函数里,你需要根据目标页面的交互方式,模拟修改筛选条件的操作(比如输入不同关键词、切换下拉选项等),确保每次抓取的是不同的JSON数据。
  • XHR数据获取:如果页面的XHR请求没有暴露全局变量,你可以用Nightmare的har方法捕获网络请求,从中提取对应的JSON响应:
    .har()
    .then(har => {
      const xhrRequest = har.log.entries.find(entry => entry.request.url.includes('你的API接口关键词'));
      return JSON.parse(xhrRequest.response.content.text);
    })
    
  • 并发与冲突处理:如果抓取频率很高,要注意文件读写的并发冲突问题。可以用lockfile包加文件锁,或者将任务改成队列执行,避免多个进程同时读写主JSON文件。
  • 错误处理:代码里已经加了基础的错误捕获,生产环境中可以再加更完善的异常处理(比如抓取失败时重试、文件写入失败时告警等)。

可选优化方向

如果主JSON数据量很大,本地文件读写会越来越慢,你可以考虑将主数据存储到数据库(比如MongoDB):

  • 用MongoDB的findOne配合sort({id: -1})快速获取最大ID;
  • 用insertMany批量插入处理后的新数据,比文件读写更高效、更安全。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:38:08