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)
相关推荐
fruge6 分钟前
纯css制作声波扩散动画、js+css3波纹催眠动画特效、【css3动画】圆波扩散效果、雷达光波效果完整代码
javascript·css·css3
neter.asia14 分钟前
vue中如何关闭eslint检测?
前端·javascript·vue.js
~甲壳虫15 分钟前
说说webpack中常见的Plugin?解决了什么问题?
前端·webpack·node.js
光影少年34 分钟前
vue2与vue3的全局通信插件,如何实现自定义的插件
前端·javascript·vue.js
Rattenking39 分钟前
React 源码学习01 ---- React.Children.map 的实现与应用
javascript·学习·react.js
~甲壳虫1 小时前
说说webpack中常见的Loader?解决了什么问题?
前端·webpack·node.js
~甲壳虫1 小时前
说说webpack proxy工作原理?为什么能解决跨域
前端·webpack·node.js
熊的猫2 小时前
JS 中的类型 & 类型判断 & 类型转换
前端·javascript·vue.js·chrome·react.js·前端框架·node.js
别拿曾经看以后~3 小时前
【el-form】记一例好用的el-input输入框回车调接口和el-button按钮防重点击
javascript·vue.js·elementui
川石课堂软件测试3 小时前
性能测试|docker容器下搭建JMeter+Grafana+Influxdb监控可视化平台
运维·javascript·深度学习·jmeter·docker·容器·grafana