自动打卡Bete 0.1.0

起风了 Lv3

此为疫情期间学校要求每天需要在企业微信打卡而写的自动打卡脚本,挂载到我那2g2h的阿里云服务器,就可以一劳永逸了~

autodaka.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// 导入模块
const puppeteer = require('puppeteer');
const mysql = require('mysql');
// 读取json配置文件
var config=require("./config.json");
// 创建mysql连接(配置)
const conn = mysql.createConnection({
// 主机ip(域名)
host: config.sql.host,
// 登录用户名
user: config.sql.user,
// 登录密码
password: config.sql.password,
// 指定数据库服务端口
port: config.sql.port,
// 要读取的数据库
database: config.sql.database
});
// 打卡功能
function daka(username, password) {
// 异步执行
(async () => {
// 定义浏览器窗口
const browser = await puppeteer.launch({
// 定义默认视图大小
defaultViewport: {
width: 600,
height: 2600
},
// Linux下截图需要设置
args:['--no-sandbox', '--disable-setuid-sandbox'],
// 无头模式,即 后台运行,不弹出浏览器
headless: true
});
// 定义新页面
const page = await browser.newPage();
//
const context = browser.defaultBrowserContext();
// 屏蔽定位
await context.overridePermissions('https://myddc.usx.edu.cn/', ['geolocation']);
// 虚拟定位
await page.setGeolocation({
// 纬度
latitude: parseFloat(config.map.latitude) ,
// 经度
longitude: parseFloat(config.map.longitude)
})
// 跳转url
await page.goto('https://ca.usx.edu.cn/cas/login?service=https%3A%2F%2Fmyddc.usx.edu.cn%2Fwebroot%2Fdecision%2Fview%2Fform%3Fop%3Dh5%26viewlet%3Dxxkj%252Fmobile%252Fbpa%252Fbpa.frm#/form');
// 输入用户名和密码
await page.type("#username", username, {delay: 100});
await page.type("#password", password, {delay: 100});
// 模拟键盘按回车键
await page.keyboard.press('Enter');
// 等待页面跳转
await Promise.all([page.waitForNavigation()]);
// 等待3000毫秒,即3秒
await page.waitForTimeout(3000);
try {
// 寻找已打卡的tag
await page.waitForXPath("//div[contains(text(),'今日已打卡!')]", 5000);
// let btn=(await page.$x("//div[contains(text(),'确定')]"))[0];
// if(btn)btn.click();
await page.waitForTimeout(3000);
// 截图
await page.screenshot({
path: './Screenshots/'+username+'.png'
});
} catch {
// 定位checkbox
await page.waitForXPath("//div[text()='同意签订承诺书']/../div[1]", 5000);
let btn_prm = (await page.$x("//div[text()='同意签订承诺书']/../div[1]"))[0];
// 点击定位到的checkbox
if (btn_prm) btn_prm.click();
await page.waitForTimeout(3000);
// 等待Xpath元素出现
await page.waitForXPath("//*[text()='提交']", 5000);
// 定位“提交”按钮
let btn_sub = (await page.$x("//*[text()='提交']"))[0];
// 点击
if (btn_sub) btn_sub.click();
await page.waitForTimeout(3000);
// 截图
await page.screenshot({
path: './Screenshots/'+username+'.png'
});
}
// 延迟3秒
await page.waitForTimeout(3000)
// 关闭浏览器
await browser.close();
})();
}

// 连接mysql
conn.connect();
// sql语句
var sql = 'select * from user_info';
// 执行查询
conn.query(sql, function (err, result) {
if (err) {
console.log('[SELECT ERROR] - ', err.message);
return;
}
// 读取用户列表执行打卡
for (let i in result) {
daka(result[i].username,result[i].password);
}
});
// 关闭连接
conn.end();

autoemail.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# 导入库
import os
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
import smtplib
from email.header import Header
from email.mime.multipart import MIMEMultipart
from email.utils import parseaddr, formataddr
import pandas as pd
import sqlalchemy as sql
import json

# 读取json配置文件
with open('./config.json','rb')as js:
config=json.load(js)
# email的服务器和服务端口号
host = config['email']['host']
port = config['email']['port']
# 采用SSL连接
s = smtplib.SMTP_SSL(host)
# 连接email服务器
s.connect(host, port)

def _format_addr(s):
name, addr = parseaddr(s)
return formataddr((Header(name, 'utf-8').encode(), addr))
# 读取图片列表
pngs = os.listdir(f'./Screenshots')
# 创建数据库连接配置
engine = sql.create_engine(f"mysql+pymysql://{config['sql']['user']}:{config['sql']['password']}@{config['sql']['host']}:{config['sql']['port']}/{config['sql']['database']}")
# sql语句
sql='select * from user_info'
# 执行sql语句,返回dataframe格式数据
df=pd.read_sql(sql,engine)
# 发送列表(dict),此时为空
send_list_dict={}
# 将数据塞到发送列表里
for row in df.itertuples(index=True,name='Pandas'):
send_list_dict[getattr(row,'username')]=getattr(row,'email')
# 发送方email-address
from_addr = config['email']['from_addr']
# 发送方email-password
password =config['email']['from_pwd']
# 登录邮箱服务
s.login(user=from_addr, password=password)
# 遍历图片(其实也是遍历用户,autodaka会为每个用户生成截图,因此不用担心遗漏的问题)
for png in pngs:
msg = MIMEMultipart()
# email内容,可以写h5
msg.attach(MIMEText('<html><body style:"margin:0 auto;"><h1>结果截图:</h1>' +
'<p><img src="cid:0"></p>' +
'</body></html>', 'html', 'utf-8'))
msg.attach(MIMEText('打卡结果', 'plain', 'utf-8'))
# 为email加一些参数
with open(f'./Screenshots/{png}', 'rb') as f:
mime = MIMEBase('image', 'png', filename=png)
mime.add_header('Content-Disposition', 'attachment', filename=png)
mime.add_header('Content-ID', '<0>')
mime.add_header('X-Attachment-Id','0')
mime.set_payload(f.read())
encoders.encode_base64(mime)
msg.attach(mime)
to_addr = send_list_dict[png.split('.')[0]]
msg['From'] = _format_addr('打卡小助手 <%s>' % from_addr)
msg['To'] = _format_addr('管理员 <%s>' % to_addr)
msg['Subject'] = Header('今日打卡结果反馈:', 'utf-8').encode()
# 发送邮件
s.sendmail(from_addr, [to_addr], msg.as_string())
# 退出email服务
s.quit()
  • 标题: 自动打卡Bete 0.1.0
  • 作者: 起风了
  • 创建于 : 2023-10-30 10:16:01
  • 更新于 : 2026-09-26 11:50:56
  • 链接: https://www.wangcac.me/2023/10/30/自动打卡Bete-0-1-0/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
目录
自动打卡Bete 0.1.0