最近领导给我一个Excel表格,让我检查下其中的 Url 是否有效。作为一个开发人员,我内心是拒绝的,一个一个点击测试,估计手抽筋也测试不完。我想,人类的进步,源于使用工具,那我就写个程序跑一下吧,然后我去喝杯茶。
思路
- 读取 Excel 中数据
- 检测 url 是否有效
- 把数据写入 Excel
- 检查核对下数据
Excel 格式示例
序号 | 分类 | 名称 | 网址 | 状态 |
---|---|---|---|---|
1 | A类 | 某某网 | http://www.xxx.com/ | 未检测 |
2 | A类 | 某某网 | http://www.xxx.com/ | 未检测 |
3 | A类 | 某某网 | http://www.xxx.com/xxx | 未检测 |
撸起袖子,动手干吧
根据思路, 整理下代码吧
新建 index.js
const urlIsSuccess = require('./urlIsSuccess')
const { readSheets, getSheet, sheetsBuffer, writeFile } = require('./xlsx')
const entryfilePath = `${ __dirname }/test.xlsx` // 输入的 Excel 文件
const outFilePath = `${ __dirname }/out_test.xlsx` // 输出的 Excel 文件
const sheetIndex = 0; // Excel 的 Sheet 索引
const urlColIndex = 3 // Excel 中 网址 所在的列索引
const statusColIndex = 4 // Excel 中 状态 所在的列索引
let sheets = readSheets(entryfilePath) // 读取 Excel 中数据
const sheet = getSheet(sheets, sheetIndex) // 读取 Excel 中 Sheet 数据
const isUrl = url => {
if (!url) return false
return /\s*http(s)?:\/\/.+/.test(url)
}
// 循环sheet表中的行数据
// 返回一个Promise数组, 用于 Promise.all 使用
let promises = sheet.map(rows => {
const url = rows[ urlColIndex ]
if (isUrl(url)) {
return urlIsSuccess(url).then(res => {
// 返回检测的状态码, 写入状态格
rows[ statusColIndex ] = res
return Promise.resolve(rows)
})
}
return Promise.resolve(rows)
})
Promise.all(promises).then((res) => {
sheets[ sheetIndex ].data = res;
const buffer = sheetsBuffer(sheets)
writeFile(buffer, outFilePath)
}).catch(err => {
console.log('err=', err)
})
操作 Excel 中数据
需要安装node-xlsx npm install node-xlsx --save
新建 xlsx.js
const fs = require("fs")
const xlsx = require('node-xlsx').default;
// 读取Excel表全部数据
const readSheets = (filePath) => {
if (!filePath) return []
return xlsx.parse(filePath)
}
// 读取Excel表中Sheet数据
const getSheet = (sheets, nameOrIndex) => {
if (nameOrIndex === undefined) return sheets
if (typeof nameOrIndex === 'string') {
return sheets.find(sheet => nameOrIndex === sheet.name)?.data
}
if (typeof nameOrIndex === 'number') {
return sheets[ nameOrIndex ]?.data
}
throw new Error(`nameOrIndex 不合法: ${ nameOrIndex }`)
}
const sheetsBuffer = (sheets) => {
if (!sheets) {
throw new Error(`sheets 参数是必填项`)
}
return xlsx.build(sheets)
};
// 写入文件,需要提前手动创建
const writeFile = (buffer, outFilePath) => {
fs.writeFile(outFilePath, buffer, function (err) {
if (err) {
console.log("写入失败: " + err);
return;
}
console.log("写入完成");
});
}
module.exports = {
readSheets,
getSheet,
sheetsBuffer,
writeFile
}
检测 url 是否有效
使用 nodejs 的 child_process.exec(),调用 命令行curl命令, 根据返回的错误状态码或者HTTP状态码,判断 URL 是否有效
新建 urlIsSuccess.js
const child_process = require("child_process");
const urlIsSuccess = (url) => {
if (!url) {
return Promise.resolve('')
}
// 微信内置浏览器 "Mozilla/5.0 AppleWebKit/600 Mobile MicroMessenger/6.0"
const userAgent = '-A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36"'
const curl = `curl -I ${ userAgent } ${ url }`
return new Promise((resolve, reject) => {
child_process.exec(curl, function (err, stdout, stderr) {
console.log(url, '完成')
if (err) {
resolve(err.code || '失败')
return
}
let status = stdout.split('\n')
if (status.length) {
let code = status[ 0 ].match(/\s(\d{3})\s/)
if (code && code[ 1 ]) {
status = +code[ 1 ]
}
}
if (!status) {
status = stdout;
}
resolve(status || '成功')
});
})
}
module.exports = urlIsSuccess;
注意
有部分网站,做了人机检测, 需要对请求头等进行配置,否则通过curl访问会失败