文章目录
用puppeteer实现网页的自动化
描述
公司要打卡,老爱忘记打卡的不行。根据现有的条件想了一种方案,现在实现。
主要思路:
1、如何查询有没有打卡
2、如何通知我
如何查询有没有打卡
第一种:使用网页查询
第二种:使用app查询
我们选第一种网页查询
如何通知我
第一种:使用微信通知
第二种:使用邮箱通知(在手机绑定邮箱后,有新邮件手机会下拉框通知)
实现
网页查询
选用puppeteer
打开并登陆
const browser = await puppeteer.launch({ headless: false });//打开在调试模式
const page = await browser.newPage();
await page.goto("http://www.a.com");//打开的网站
await page.type("#username", "username");//用户名
await page.type("#password", "password");//密码
await page.click("#loginnew");//点击登陆按钮
await delay(10000);//登录后资源准备时间较长,延时10秒
delay函数
function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
获取排班和打卡记录
此处不再贴具体代码,主要讲一下用到的函数和逻辑
iframe
在网页中,之前都是用上面的page操作,但登陆后的网页它有嵌套网页,这时候要找到iframe元素
let frames = await page.frames();
let iframe = frames.find((frame) => frame.name() === "000000");
元素不好点击
let element = await iframe.$(
"#aaa"
);
await element.evaluate((b) => b.click());
await delay(3000);
数据整理
将网页中需要的数据整理处理,放到对象中。
一个排班表,另一个打卡表
schedulingTable = await iframe.evaluate(
getTbodyTextArray,
"#table1"
);
checkInTable = await iframe.evaluate(
getTbodyTextArray,
"#table"
);
function getTbodyTextArray(selector) {
// 获取<tbody>元素
const tbodyElement = document.querySelector(selector);
// 初始化一个数组来存储每个子节点的文本内容
const tbodyTextArray = [];
// 遍历<tbody>中的每个子节点
tbodyElement.childNodes.forEach((childNode) => {
// 检查节点类型是否为元素节点
if (childNode.nodeType === 1) {
// 将子节点的文本内容添加到数组中
let array = [];
for (const key in childNode.childNodes) {
if (childNode.childNodes[key].childNodes) {
array.push(
childNode.childNodes[key].childNodes[0].textContent.trim()
);
continue;
}
array.push("");
}
// 将子节点的文本内容添加到数组中
tbodyTextArray.push(array);
}
});
// 返回包含<tbody>内容的数组
return tbodyTextArray;
}
打卡结果判断
判断是工作日还是非工作日
let { checkInTable, schedulingTable } = await getTableValues();
if(checkInTable==null){
return {result :false,reason:'获取打卡记录失败'}
}
if(checkInTable==null){
return {result :false,reason:'获取排班记录失败'}
}
let scheduling = null
for (let i = 0; i < schedulingTable.length; i++) {
const element = schedulingTable[i];
if(element[0]==date){
scheduling = element
}
}
if(schedule==null){
return {result :false,reason:'无法获取排班信息'}
}
if(scheduling[4]!='工作日'){
return {result :true,reason:'当前非工作日'}
}
判断是否打卡
let dates = date.split('-')
let md = dates[1]+'-'+dates[2]
let cTime = ''
for (let i = 0; i < checkInTable.length; i++) {
const element = checkInTable[i];
if(element[0].includes(md)){
cTime = element[chi]//chi是打卡的时间
}
}
if(cTime){
return {result :true,reason:'打卡时间:'+cTime}
}else{
return {result :false,reason:'未打卡'}
}
chi打卡时间
一般而言,一天只需要打卡四次。
早上上班,中午下班,中午上班,下午下班
chi是获取班次的table列
定时器
一天需要在指定的时间去获取打卡记录,用定时器触发检测。
schedule.scheduleJob("0 5 8 * * *", function () {
task(1);
});//早上8点前的打卡记录
schedule.scheduleJob("0 5 12 * * *", function () {
task(2);
});
schedule.scheduleJob("0 20 12 * * *", function () {
task(3);
});//中午下班获取两次
schedule.scheduleJob("0 5 14 * * *", function () {
task(4);
});//下午上班的打卡记录
schedule.scheduleJob("0 20 18 * * *", function () {
task(5);
});
schedule.scheduleJob("0 40 18 * * *", function () {
task(6);
});//下午下班获取两次
发邮件
let date = dayjs().format('YYYY-MM-DD')
let result = null
switch (key) {
case 1:
result = await main(date,3,0);
break;
case 2:
case 3:
result = await main(date,4,0);
break;
case 4:
result = await main(date,5,0);
break;
case 5:
case 6:
result = await main(date,6,0);
break;
default:
break;
}
options.text = result.reason
await sendMail(options)
将代码变为服务
用pm2把实现的代码变为服务,运行在我们电脑后台。
写在最后
本文只提供一种思路的实现方法,具体的需要自行调整。