基于Nightmare.js的JSON合并需求:生成带递增ID的主JSON
解决方案:基于Nightmare.js的JSON合并与递增ID分配方案
我来给你梳理一个可行的实现方案,刚好之前做过类似的批量抓取合并需求,结合Nightmare.js的特性,咱们可以按以下步骤来完成:
核心思路
咱们的核心目标是持续将新抓取的JSON对象合并到主JSON中,并为新对象分配不重复的递增ID。具体逻辑是:
- 持久化存储主JSON(比如本地文件),每次抓取前先读取它;
- 找到主JSON中当前最大的ID值;
- 用Nightmare.js抓取到新的JSON后,给每个对象替换成从
maxID + 1开始的递增ID; - 将处理后的新对象合并到主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
相关产品推荐
相关产品推荐

