本工具仅供学习使用,大家注意遵守学校规章制度.如有身体不适及时上报.
使用selenium完成健康打卡
一年前,写了selenium打卡的代码.一年来也有不断地更新版本,添加邮件通知功能,http get请求进行腾讯文档标注(后来腾讯文档改版,隐藏了接口).以及用post登入验证打卡是否成功.到今天,算是完成了2.0版本的,现在整个程序觉得还蛮满意的(强迫症的满足).
虽然selenium已经很方便的,但我还是觉得不够优雅,使用浏览器+driver的方式太臃肿了,相比于图形操作的方式,我更喜欢命令行的方式.
有不少同学会想找我要代码,但是我想介绍的时候,即使是计算机专业的同学介绍还是蛮麻烦的,毕竟需要配置driver环境变量,还要下驱动.非计算机专业的同学大概率没得python环境就更难介绍了.(后续查好像selenium也可以打包,不确定没装驱动可不可以)
其实用selenium我个人觉得不稳定因素贼多,老是会出错,所以我会在一年里用了很多方法处理,比如邮件确定,try catch捕获异常,用post登入确保一定登上.这一系列的操作,让程序又臃肿起来了.
第二个不稳定因素是webdriver的问题,Chrome老自动更新.driver也要更新挺烦的
抓包登入接口.此处有一个问题需要处理:
登入的密码其实与我们的密码不一致,是经过算法加密的.所以想要直接使用这个接口的话,需要对代码进行处理.我找了好哥们儿帮我找到了加密方式,解决了这个问题.其实也有替代方案,要哪个账号打卡就登入一下抓包就能拿到了,不过不优雅.
这个接口能得到的响应:
这里的响应会有msg,用于判断是否打卡
jnuid后续post的重要凭证
写的时候发现,暴露的东西有点点多,我还是把具体步骤隐藏起来吧,下面的代码是可以用的,但是需要自己抓包接口.另外我还发现了一个问题,觉得系统不是很安全.我还是不要暴露了
然后发现打卡并没有用session.如果有的话其实更方便,用session.request()
1.我将代码打包成exe文件(可直接在Windows10运行).这里我修改了代码为本地版本的,不再发邮件而是使用log.txt的形式进行记录.使用的打包工具是pyinstaller我这里打包的是带命令行界面版的
2.以account.txt作为账户输入.格式为账户 (空格) 密码 (空格) 姓名
如果多个账户换行即可.示例:
20xxxxx xxxxx 张三
20xxxxx xxxxx 李四
相应的打卡记录会显示在同一目录下的log.txt中
3. Windows定时任务定时执行代码.(可以看后面的参考资料)
以下为批量打卡程序
import post_daka_success
from email.mime.text import MIMEText
import smtplib
account = [['账号','密码','姓名','邮箱']]
msg_from = '' # 发送方邮箱
passwd = '' # 填入发送方邮箱的授权码
msg_to = [''] # 收件人邮箱
subject = "打卡邮件" # 主题
content = ""
for acc in account:
obj = post_daka_success.daka(acc[0],acc[1])
obj.run()
if obj.check():
content += "程序已经为"+acc[2]+"打卡\n"
else:
content += acc[2]+"未打卡\n"
s = smtplib.SMTP_SSL("smtp.qq.com", 465)
msg = MIMEText(content)
msg['Subject'] = subject
msg['From'] = msg_from
msg['To'] = account[0][3]
s.login(msg_from, passwd)
s.sendmail(msg_from, account[0][3], msg.as_string())
以下为打卡用的程序
# -*- coding:utf-8 -*-
import requests
import json
import base64
from Crypto.Cipher import AES
import time
from cryptography.hazmat.primitives.ciphers import algorithms
from cryptography.hazmat.primitives import padding
class daka:
headers = {
"accept": "application/json, text/plain, */*",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
"content-type": "application/json",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Safari/537.36"}
sucess = "登录成功,今天已填写"
def __init__(self, account, password):
super().__init__()
self.account = account
self.password = password
self.body = {
"username": account,
"password": self.jiami(password)}
self.body = json.dumps(self.body)
def pkcs7_padding(self, data):
padder = padding.PKCS7(algorithms.AES.block_size).padder()
padded_data = padder.update(data.encode('utf-8'))+padder.finalize()
return padded_data
# 将密码转为加密后的代码
def jiami(self, data):
key = 'xAt9Ye&SouxCJziN'.encode('utf-8')
cryptor = AES.new(key, AES.MODE_CBC, key)
res = base64.b64encode(cryptor.encrypt(self.pkcs7_padding(
data))).decode().replace('/', '_').replace('+', '-')
res = list(res)
res[-2] = "*"
res = "".join(res)
return res
# 登入
def login(self):
url = ''#登入的网址
res_login = requests.post(
url, data=self.body, headers=self.headers)
res_login_data = json.loads(res_login.text)
print(res_login_data)
self.res_login_data = res_login_data
# 获取打卡需要的相关信息
def get_info_data(self):
res_login_data = self.res_login_data
get_info_data = {
}
get_info_data['jnuid'] = res_login_data['data']['jnuid']
get_info_data['idType'] = '1'
# print(get_info_data)
get_info_data = json.dumps(get_info_data)
info_url = ''#获取信息的网址
res_info_data = requests.post(
info_url, data=str(get_info_data).encode('utf-8'), headers=self.headers)
res_info_data = json.loads(res_info_data.text)
self.res_info_data = res_info_data
# print(res_info_data)
def post(self):
res_info_data = self.res_info_data
daka_post_url = ""#post的网址
post_data = {
}
post_data['mainTable'] = {
}#这里需要抓包填一下学校的地址
post_data['mainTable']['leaveTransportationOther'] = res_info_data['data']['mainTable']['leaveTransportationOther']
post_data['mainTable']['way2Start'] = res_info_data['data']['mainTable']['way2Start']
post_data['mainTable']['language'] = res_info_data['data']['mainTable']['language']
post_data['mainTable']['declareTime'] = res_info_data['data']['declare_time']
post_data['mainTable']['personNo'] = res_info_data['data']['jnuId']
post_data['mainTable']['personName'] = res_info_data['data']['xm']
post_data['mainTable']['sex'] = res_info_data['data']['xbm']
post_data['mainTable']['professionName'] = res_info_data['data']['zy']
post_data['mainTable']['collegeName'] = res_info_data['data']['yxsmc']
post_data['mainTable']['phoneArea'] = res_info_data['data']['mainTable']['phoneArea']
post_data['mainTable']['phone'] = res_info_data['data']['mainTable']['phone']
post_data['mainTable']['assistantName'] = res_info_data['data']['mainTable']['assistantName']
post_data['mainTable']['assistantNo'] = res_info_data['data']['mainTable']['assistantNo']
post_data['mainTable']['className'] = res_info_data['data']['mainTable']['className']
post_data['mainTable']['linkman'] = res_info_data['data']['mainTable']['linkman']
post_data['mainTable']['linkmanPhoneArea'] = res_info_data['data']['mainTable']['linkmanPhoneArea']
post_data['mainTable']['linkmanPhone'] = res_info_data['data']['mainTable']['linkmanPhone']
post_data['mainTable']['personHealth'] = res_info_data['data']['mainTable']['personHealth']
post_data['mainTable']['temperature'] = res_info_data['data']['mainTable']['temperature']
post_data['mainTable']['personHealth2'] = res_info_data['data']['mainTable']['personHealth2']
post_data['mainTable']['schoolC1'] = res_info_data['data']['mainTable']['schoolC1']
post_data['mainTable']['currentArea'] = res_info_data['data']['mainTable']['currentArea']
post_data['mainTable']['personC4'] = res_info_data['data']['mainTable']['personC4']
post_data['mainTable']['otherC4'] = res_info_data['data']['mainTable']['otherC4']
post_data['mainTable']['isPass14C1'] = res_info_data['data']['mainTable']['isPass14C1']
post_data['mainTable']['isPass14C2'] = res_info_data['data']['mainTable']['isPass14C2']
post_data['mainTable']['isPass14C3'] = res_info_data['data']['mainTable']['isPass14C3']
post_data['secondTable'] = {
}
post_data['secondTable']['other1'] = res_info_data['data']['secondTable']['other1']
post_data['secondTable']['other3'] = res_info_data['data']['secondTable']['other3']
post_data['secondTable']['other4'] = res_info_data['data']['secondTable']['other4']
post_data['secondTable']['other5'] = res_info_data['data']['secondTable']['other5']
post_data['secondTable']['other6'] = res_info_data['data']['secondTable']['other6']
post_data['secondTable']['other7'] = res_info_data['data']['secondTable']['other7']
post_data['secondTable']['other8'] = res_info_data['data']['secondTable']['other8']
post_data['secondTable']['other9'] = res_info_data['data']['secondTable']['other9']
post_data['jnuid'] = self.res_login_data['data']['jnuid']
post_data_res = requests.post(
daka_post_url, data=json.dumps(post_data), headers=self.headers)
print(post_data_res.text)
self.post_data_res = json.loads(post_data_res.text)
#检查是否打卡成功
def check(self):
self.login()
if(self.res_login_data['meta']['msg'] == self.sucess):
print(self.res_login_data['data']['name']+'>>>>'+self.sucess)
return True
return False
def run(self):
self.login()
self.get_info_data()
self.post()
if __name__ == '__main__':
obj = daka("账户", "密码")
obj.run()
obj.yanzhen()