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)
相关推荐
燃先生._.2 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖3 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
black^sugar4 小时前
纯前端实现更新检测
开发语言·前端·javascript
理想不理想v5 小时前
webpack最基础的配置
前端·webpack·node.js
2401_857600955 小时前
SSM 与 Vue 共筑电脑测评系统:精准洞察电脑世界
前端·javascript·vue.js
2401_857600955 小时前
数字时代的医疗挂号变革:SSM+Vue 系统设计与实现之道
前端·javascript·vue.js
GDAL5 小时前
vue入门教程:组件透传 Attributes
前端·javascript·vue.js
小白学大数据5 小时前
如何使用Selenium处理JavaScript动态加载的内容?
大数据·javascript·爬虫·selenium·测试工具
2402_857583495 小时前
基于 SSM 框架的 Vue 电脑测评系统:照亮电脑品质之路
前端·javascript·vue.js