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)
相关推荐
建群新人小猿33 分钟前
会员等级经验问题
android·开发语言·前端·javascript·php
djk888844 分钟前
Layui Table 行号
前端·javascript·layui
痴憨道人1 小时前
openharmony sdk描述
javascript
loey_ln1 小时前
FIber + webWorker
javascript·react.js
lv程序媛2 小时前
el-table表头前几列固定,后面几列根据接口返回的值不同展示不同
javascript·vue.js·elementui
ZwaterZ2 小时前
el-table-column自动生成序号&&在序号前插入图标
前端·javascript·c#·vue
蒟蒻的贤2 小时前
vue学习11.21
javascript·vue.js·学习
初遇你时动了情3 小时前
uniapp 城市选择插件
开发语言·javascript·uni-app
zongzi_4944 小时前
二次封装的天气时间日历选择组件
开发语言·javascript·ecmascript
麻辣_水煮鱼4 小时前
vue数据变化但页面不变
前端·javascript·vue.js