309 lines
7.9 KiB
JavaScript
309 lines
7.9 KiB
JavaScript
import crypto from "crypto";
|
||
import axios from "axios";
|
||
/**
|
||
* 将时间戳(毫秒)转换为 yyyy-mm-dd 格式的字符串
|
||
* @param {number} timestamp - 毫秒级时间戳
|
||
* @returns {string} yyyy-mm-dd 格式日期
|
||
*/
|
||
function timestampToDate(timestamp, mode) {
|
||
const date = new Date(timestamp);
|
||
const year = date.getFullYear();
|
||
// 补零
|
||
const month = String(date.getMonth() + 1).padStart(2, "0");
|
||
const day = String(date.getDate()).padStart(2, "0");
|
||
if (!mode) {
|
||
return `${year}-${month}-${day}`;
|
||
} else {
|
||
const hours = String(date.getHours()).padStart(2, "0");
|
||
const minutes = String(date.getMinutes()).padStart(2, "0");
|
||
const seconds = String(date.getSeconds()).padStart(2, "0");
|
||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||
}
|
||
}
|
||
|
||
function md5(text, inputEncoding = "utf8", outputEncoding = "hex") {
|
||
return crypto
|
||
.createHash("md5")
|
||
.update(text, inputEncoding)
|
||
.digest(outputEncoding);
|
||
}
|
||
function getSign(timestamp) {
|
||
let secret = "cpwyyds";
|
||
let uri = "/common/message/push";
|
||
const url = uri + timestamp + secret;
|
||
const myCalc = md5(url);
|
||
let sign =
|
||
myCalc.substring(5, 13) +
|
||
myCalc.substring(29, 31) +
|
||
myCalc.substring(18, 27);
|
||
//sign 转大写
|
||
sign = sign.toUpperCase();
|
||
return sign;
|
||
}
|
||
// 微信推送
|
||
// function wechatPush(spiderName, arr) {
|
||
// for (let item of arr) {
|
||
// let timestamp = new Date().getTime();
|
||
// let sign = getSign(timestamp);
|
||
// let url = "";
|
||
// if (typeof item.urls === "string") {
|
||
// url = item.urls;
|
||
// } else {
|
||
// url = item.urls[0];
|
||
// }
|
||
// let data = {
|
||
// timestamp,
|
||
// sign,
|
||
// templateNo: "A002",
|
||
// url,
|
||
// paramList: [
|
||
// {
|
||
// key: "thing8",
|
||
// value: spiderName,
|
||
// },
|
||
// {
|
||
// key: "thing2",
|
||
// value:
|
||
// item.name.length > 20
|
||
// ? item.name.substring(0, 16) + "..."
|
||
// : item.name,
|
||
// },
|
||
// {
|
||
// key: "time14",
|
||
// value: item.publishTime,
|
||
// },
|
||
// {
|
||
// key: "time17",
|
||
// value: item.endTime,
|
||
// },
|
||
// ],
|
||
// };
|
||
// axios({
|
||
// url: "https://advert.shenlintech.com/platform/common/message/push",
|
||
// method: "post",
|
||
// data,
|
||
// });
|
||
// }
|
||
// }
|
||
// 废弃
|
||
function addToMessageQueue(spiderName, data) {
|
||
const message = {
|
||
id: Date.now() + "-" + Math.random().toString(36).substr(2, 9),
|
||
spiderName,
|
||
data,
|
||
timestamp: new Date().toISOString(),
|
||
status: "pending",
|
||
};
|
||
let queue = [];
|
||
const queueFile = "message_queue.json";
|
||
if (fs.existsSync(queueFile)) {
|
||
queue = JSON.parse(fs.readFileSync(queueFile, "utf-8"));
|
||
}
|
||
// 添加新消息
|
||
queue.push(message);
|
||
|
||
fs.writeFileSync(queueFile, JSON.stringify(queue, null, 2));
|
||
console.log(`📤 添加消息到队列: ${spiderName} - ${data.length} 条数据`);
|
||
}
|
||
|
||
async function loopCall(fn, options = {}) {
|
||
let { time, pagenumber, stopWhen, readyForNext, complete, additional } =
|
||
options;
|
||
let shouldContinue = true;
|
||
while (shouldContinue) {
|
||
try {
|
||
let result = await fn(pagenumber, additional);
|
||
// console.log(`页面 ${pagenumber} 处理完成`);
|
||
|
||
// 检查停止条件
|
||
if (stopWhen && stopWhen(pagenumber, result)) {
|
||
complete && complete(result);
|
||
shouldContinue = false;
|
||
} else {
|
||
pagenumber = readyForNext(pagenumber, result);
|
||
await new Promise((resolve) => setTimeout(resolve, time));
|
||
}
|
||
} catch (err) {
|
||
console.error("loopCall 出错:", err);
|
||
shouldContinue = false;
|
||
}
|
||
}
|
||
}
|
||
function keywordsInclude(name) {
|
||
let keywords = [
|
||
"保险",
|
||
"车险",
|
||
"非车险",
|
||
"科技",
|
||
"大模型",
|
||
"承保",
|
||
"第三方平台",
|
||
];
|
||
return keywords.some((keyword) => name.includes(keyword));
|
||
}
|
||
// 一汽专用获取公告链接的方法
|
||
function getYiqiNoticeUrl(gongGaoType, guid, version, origin) {
|
||
let baseUrl = "https://etp.faw.cn/";
|
||
//是否对参数加密
|
||
var isSecrect = false;
|
||
|
||
//候选人公示加密
|
||
if (gongGaoType == 7) {
|
||
isSecrect = true;
|
||
}
|
||
if (isSecrect) {
|
||
var url = baseUrl + "/gg/toGongGaoDetail";
|
||
guid = encodeSixF(guid);
|
||
// var params = {
|
||
// guid: guid,
|
||
// gongGaoType: gongGaoType,
|
||
// version: dealNullAndUndefined(version),
|
||
// statusCode: 1,
|
||
// isNew: 1,
|
||
// };
|
||
// try {
|
||
// await httpPostCurrent(url, params);
|
||
// } catch (err) {
|
||
// console.log(err);
|
||
// return "加密链接";
|
||
// }
|
||
return "加密链接,请直接上对应网站查看";
|
||
} else {
|
||
var url =
|
||
baseUrl +
|
||
"/gg/toGongGaoDetail?guid=" +
|
||
guid +
|
||
"&gongGaoType=" +
|
||
gongGaoType +
|
||
"&version=" +
|
||
version +
|
||
"&isNew=1";
|
||
return url;
|
||
}
|
||
}
|
||
function parseToGgDetailsParams(funcStr) {
|
||
// funcStr = "toGgDetails('6','642ed424-cd9b-4cb0-8b74-9cc868d8f95a:2','2','1','')"
|
||
|
||
const match = funcStr.match(/toGgDetails\(([^)]+)\)/);
|
||
if (match) {
|
||
// 解析参数字符串
|
||
const paramsStr = match[1];
|
||
// 简单的参数解析(处理引号包围的参数)
|
||
const params = paramsStr
|
||
.split(",")
|
||
.map((param) => param.trim().replace(/['"]/g, ""));
|
||
return params;
|
||
}
|
||
return null;
|
||
}
|
||
function encodeSixF(input) {
|
||
var keyStr =
|
||
"ABCDEFGHIJKLMNOP" +
|
||
"QRSTUVWXYZabcdef" +
|
||
"ghijklmnopqrstuv" +
|
||
"wxyz0123456789+/" +
|
||
"=";
|
||
var output = "";
|
||
var chr1,
|
||
chr2,
|
||
chr3 = "";
|
||
var enc1,
|
||
enc2,
|
||
enc3,
|
||
enc4 = "";
|
||
var i = 0;
|
||
do {
|
||
chr1 = input.charCodeAt(i++);
|
||
chr2 = input.charCodeAt(i++);
|
||
chr3 = input.charCodeAt(i++);
|
||
enc1 = chr1 >> 2;
|
||
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
|
||
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
|
||
enc4 = chr3 & 63;
|
||
if (isNaN(chr2)) {
|
||
enc3 = enc4 = 64;
|
||
} else if (isNaN(chr3)) {
|
||
enc4 = 64;
|
||
}
|
||
output =
|
||
output +
|
||
keyStr.charAt(enc1) +
|
||
keyStr.charAt(enc2) +
|
||
keyStr.charAt(enc3) +
|
||
keyStr.charAt(enc4);
|
||
chr1 = chr2 = chr3 = "";
|
||
enc1 = enc2 = enc3 = enc4 = "";
|
||
} while (i < input.length);
|
||
|
||
if (output != null && output.indexOf("=") != -1) {
|
||
var reg = new RegExp("=", "g");
|
||
var outputNew = output.replace(reg, "r1e2p3l4");
|
||
output = outputNew;
|
||
}
|
||
|
||
return output + "+*+";
|
||
}
|
||
function dealNullAndUndefined(value) {
|
||
if (typeof value == "undefined") return "";
|
||
if (value == null) return "";
|
||
if (value == "null") return "";
|
||
if (value == "undefined") return "";
|
||
return value;
|
||
}
|
||
// 企业微信消息推送
|
||
async function sendQYWechatMessage(message) {
|
||
try {
|
||
const webhook = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=7de26c43-8652-4204-9665-47a5cef58b58";
|
||
const response = await axios.post(webhook, {
|
||
msgtype: "markdown",
|
||
markdown: {
|
||
content: message
|
||
}
|
||
}, {
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
}
|
||
});
|
||
console.log(`企业微信消息推送成功: ${message}`);
|
||
return response.data; // 返回响应数据
|
||
} catch (error) {
|
||
console.error(`企业微信消息推送失败:`, error.message);
|
||
throw error; // 重新抛出错误以便调用方可以处理
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 从字符串中提取日期和标题
|
||
* @param {string} input - 输入字符串,格式如"2025.05.27 万得软件及数据服务项目单一来源采购结果公示"
|
||
* @returns {object|null} - 包含date和title属性的对象,如果不符合格式则返回null
|
||
*/
|
||
function extractDateTimeAndTitle(input) {
|
||
if (!input) return null;
|
||
|
||
// 匹配日期格式 YYYY.MM.DD 或 YYYY-MM-DD
|
||
const dateRegex = /^(\d{4}[.\-]\d{2}[.\-]\d{2})\s+(.+)$/;
|
||
const match = input.match(dateRegex);
|
||
|
||
if (match) {
|
||
return {
|
||
date: match[1],
|
||
title: match[2].trim()
|
||
};
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
export {
|
||
timestampToDate,
|
||
loopCall,
|
||
keywordsInclude,
|
||
getYiqiNoticeUrl,
|
||
parseToGgDetailsParams,
|
||
addToMessageQueue,
|
||
md5,
|
||
sendQYWechatMessage,
|
||
extractDateTimeAndTitle
|
||
// wechatPush
|
||
};
|