node.js实现遍历所有文件夹里面的js文件,提取所有的url

背景:

昨天领导找我说,有一个项目需要协助一下:找出我们平台里面所有的ajax请求的url。

因为我们的平台是商城系统,多年累积下来的项目,就js文件都大几百个,并且还是三端(web/H5/app),如果一个文件一个文件去找的话,估计需要很大的时间成本。

正好前段时间在看node知识,了解到可以通过js脚本来实现遍历文件进行读取和写入的过程。

fs模块是File System(文件系统)的缩写,它提供了一系列API用于与文件系统进行交互。你可以使用这些API来读取文件、写入文件、更改文件权限、监视文件变化等。

path模块提供了一些实用工具函数,用于处理文件和目录的路径。这些函数可以简化路径的拼接、分解、格式化和转换等工作。

readline模块用于逐行读取文件内容或来自其他可读流(如标准输入)的数据。这对于处理大型文件或需要与用户进行交互式文本输入的场景非常有用。

javascript 复制代码
// 准备工作,引入需要的api
const fs = require('fs');  
const path = require('path');  
const readline = require('readline');  

因为文件夹里面可能会存在多个文件夹或者多个文件,需要我们通过递归去遍历文件夹里面的文件

定义文件路径

javascript 复制代码
// 指定要遍历的起始文件夹路径  
const startDirPath = 'xxx'; 
// 输出文件路径,最好是采用绝对路径
const outputFilePath = 'xxx'; 

清空写入的文件的内容

javascript 复制代码
// 使用fs.truncate清空文件内容  
fs.truncate(outputFilePath, 0, () => {});

递归遍历文件内容并写入文件

javascript 复制代码
traverseDirectory(startDirPath);

// 递归遍历文件夹的函数  
function traverseDirectory(dirPath) {  

    fs.readdir(dirPath, { withFileTypes: true }, (err, files) => {  
        if (err) {  
            console.error(`Error reading directory ${dirPath}: ${err}`);  
            return;  
        }  
        files.forEach(file => {  
            const fullPath = path.join(dirPath, file.name);  
  
            if (file.isDirectory() && file.name !== 'node_modules') {  
                traverseDirectory(fullPath); // 递归遍历  
            } else if (file.isFile() && path.extname(file.name).toLowerCase() === '.js') {  
                // 读取JS文件  
                const rl = readline.createInterface({  
                    input: fs.createReadStream(fullPath),  
                    crlfDelay: Infinity  
                });  
  
                let matchedLines = [];  
  
                rl.on('line', (line) => {  
                    // 使用正则表达式找到所有被引号包裹的字符串  
                    const quoteRegex = /(['"])\/([\/\w]+)\1/g;
                    let match;  
  
                    while ((match = quoteRegex.exec(line)) !== null) { 
                        matchedLines.includes(match[0]) ? null : matchedLines.push(match[0]);  
                    }  
                });  
  
                rl.on('close', () => {  
                    // 将所有匹配的字符串写入输出文件  
                    if (matchedLines.length > 0) { 
                        fs.appendFile(outputFilePath, matchedLines.join('\n') + '\n', (err) => {  
                            if (err) {  
                                console.error(`Error writing to ${outputFilePath}: ${err}`);  
                            } else {  
                              console.log(outputFilePath, 'outputFilePath')
                                console.log(`Processed file: ${fullPath}, ${matchedLines.length} matches found.`);  
                            }  
                        });  
                    }  
                });  
            }  
        });  
    });  
}  

可能由于我们的正则匹配格式并没有很严谨,或者说我们只需要某些特定的数据,这个时候,我们可以对获取到的数据进行移除特定词的过滤。

javascript 复制代码
// 关键词列表  
const keywords = ['submit', 'add', 'update', 'save', 'confirm', 'faq', 'cn', 'page', 'list', 'send', 'join', 'modelInventory', 'mem', 'mcom', 'trade', 'order', 'corporateProcurement', 
  'enterprisePay', 'delete', 'cancel', 'del', 'check', 'upload'];  

// 检查字符串是否包含任何关键词(不区分大小写)  
function containsKeyword(str) {  
    return keywords.some(keyword => str && str.toLowerCase().includes(keyword));  
}  


// 在写入文件之前进行判断
while ((match = quoteRegex.exec(line)) !== null) { 
    const quotedString = match[2];  
    if (containsKeyword(quotedString)) {  
        // 如果引号内的内容包含关键词,则记录整个匹配的字符串
        matchedLines.includes(match[0]) ? null : matchedLines.push(match[0]);  
    }  
} 

如果您想对获取到的数据进行排序或者做一些其他的操作,可以将输入传给外面的变量

javascript 复制代码
let resultList = [];

rl.on('close', () => {  
    // 将所有匹配的字符串写入输出文件  
    if (matchedLines.length > 0) { 
        resultList = [...resultList, ...matchedLines];
        console.log(outputFilePath, 'outputFilePath')
        console.log(`Processed file: ${fullPath}, ${matchedLines.length} matches found.`);  
    } 
});  

总结代码

javascript 复制代码
const fs = require('fs');  
const path = require('path');  
const readline = require('readline');  
  
// 关键词列表  
const keywords = ['submit', 'add', 'update', 'save', 'confirm', 'faq', 'cn', 'page', 'list', 'send', 'join', 'modelInventory', 'mem', 'mcom', 'trade', 'order', 'corporateProcurement', 
  'enterprisePay', 'delete', 'cancel', 'del', 'check', 'upload'];  
// 指定要遍历的起始文件夹路径  
const startDirPath = 'D:\\projects\\ecm\\html\\front'; // 替换为你的文件夹路径  
// 输出文件路径  
const outputFilePath = 'C:\\Users\\cheney_chen\\Desktop\\中文站接口url.txt';  

let resultList = [];
  
// 检查字符串是否包含任何关键词(不区分大小写)  
function containsKeyword(str) {  
    return keywords.some(keyword => str && str.toLowerCase().includes(keyword));  
}  

// 递归遍历文件夹的函数  
function traverseDirectory(dirPath) { 
    fs.readdir(dirPath, { withFileTypes: true }, (err, files) => {  
        if (err) {  
            console.error(`Error reading directory ${dirPath}: ${err}`);  
            return;  
        }  
        files.forEach(file => {  
            const fullPath = path.join(dirPath, file.name);  
            if (file.isDirectory() && file.name !== 'node_modules') {  
                traverseDirectory(fullPath); // 递归遍历  
            } else if (file.isFile() && path.extname(file.name).toLowerCase() === '.js') {  
                // 读取JS文件  
                const rl = readline.createInterface({  
                    input: fs.createReadStream(fullPath),  
                    crlfDelay: Infinity  
                });  
                let matchedLines = []; 
                rl.on('line', (line) => {  
                    // 使用正则表达式找到所有被引号包裹的字符串  
                    const quoteRegex = /(['"])\/([\/\w]+)\1/g;
                    let match;  
  
                    while ((match = quoteRegex.exec(line)) !== null) { 
                        const quotedString = match[2];  
                        if (containsKeyword(quotedString)) {  
                            // 如果引号内的内容包含关键词,则记录整个匹配的字符串
                            matchedLines.includes(match[0]) ? null : matchedLines.push(match[0]);  
                        }  
                    }  
                });  
  
                rl.on('close', () => {  
                    // 将所有匹配的字符串写入输出文件  
                    if (matchedLines.length > 0) { 
                      resultList = [...resultList, ...matchedLines];
                      console.log(outputFilePath, 'outputFilePath')
                      console.log(`Processed file: ${fullPath}, ${matchedLines.length} matches found.`);  
                    } 
                });  
            }  
        });  
    });  
}  

// 使用fs.truncate清空文件内容  
fs.truncate(outputFilePath, 0, () => {}); 
traverseDirectory(startDirPath);

setTimeout(()=>{
  resultList = [...new Set(resultList)];
  resultList = resultList.map((item, index) => (index + 1) + '、' + item)
  // 写入文件
  fs.appendFile(outputFilePath, resultList.join('\n') + '\n', (err) => {  
    if (err) {  
        console.error(`Error writing to ${outputFilePath}: ${err}`);  
    }
  });
}, 5000)
相关推荐
Hello-Mr.Wang1 分钟前
vue3中开发引导页的方法
开发语言·前端·javascript
程序员凡尘28 分钟前
完美解决 Array 方法 (map/filter/reduce) 不按预期工作 的正确解决方法,亲测有效!!!
前端·javascript·vue.js
北岛寒沫5 小时前
JavaScript(JS)学习笔记 1(简单介绍 注释和输入输出语句 变量 数据类型 运算符 流程控制 数组)
javascript·笔记·学习
everyStudy5 小时前
JavaScript如何判断输入的是空格
开发语言·javascript·ecmascript
无心使然云中漫步6 小时前
GIS OGC之WMTS地图服务,通过Capabilities XML描述文档,获取matrixIds,origin,计算resolutions
前端·javascript
Bug缔造者6 小时前
Element-ui el-table 全局表格排序
前端·javascript·vue.js
xnian_7 小时前
解决ruoyi-vue-pro-master框架引入报错,启动报错问题
前端·javascript·vue.js
麒麟而非淇淋8 小时前
AJAX 入门 day1
前端·javascript·ajax
2401_858120538 小时前
深入理解MATLAB中的事件处理机制
前端·javascript·matlab
阿树梢8 小时前
【Vue】VueRouter路由
前端·javascript·vue.js