每天手动打卡实在太繁琐了,作为coder,有没有捷径可走?理论上可以有!
前边的话:本博客仅讨论技术实现,疫情防控需谨慎,如有异常请及时上报。
将iPhone和电脑连在同一wifi下,设置手机http代理,安装SSL证书,安装并信任描述文件。
点击手机端打卡界面,在Charles上得到手机端的HTTP请求列表;在手机端填写打卡页面并提交,在对应HTTP使用Charles的compose功能获取手机发送的json文件。
(具体细节可参考y2777an的博客)
代码思路为,先登录北航sso并验证(login()函数
),获取上次提交的信息并进行修改(get_info()函数
),随后向服务器提交json文件并验证(post()函数)。bark()函数
基于ios APP bark,实现了打卡失败时向iPhone自动发送提醒的功能。代码添加了日志功能。
具体代码如下所示:
# -*- coding: utf-8 -*-
# /usr/bin/python
import requests
import json
import time
import sys
import urllib.request
login_url = "https://app.buaa.edu.cn/uc/wap/login?redirect=https%3A%2F%2Fapp.buaa.edu.cn%2Fncov%2Fwap%2Fdefault%2Findex%3Ffrom%3Dhistory"
login_check_url = "https://app.buaa.edu.cn/uc/wap/login/check"
base_url = "https://app.buaa.edu.cn/xisuncov/wap/open-report/index"
save_url = "https://app.buaa.edu.cn/xisuncov/wap/open-report/save"
class ClockIn(object):
def __init__(self, username, password, bark_id):
self.username = username
self.password = password
self.bark_id = bark_id
self.log_path = './log.txt'
self.sess = requests.Session()
def login(self):
""" Login to BUAA platform."""
res = self.sess.get(login_url)
if res.status_code != 200:
error_1 = "{} failed to login platform,fail status code is {}.".format(self.username, res.status_code)
self.bark(error_1)
#print(error_1)
raise Exception(error_1)
data = {'username': self.username, 'password': self.password, }
responce = self.sess.post(url=login_check_url, data=data)
responce_decode = json.loads(responce.content.decode())
if responce_decode['e'] != 0:
error_2 = "{} failed in the login process and the reason is {}.".format(self.username, responce_decode['m'])
self.bark(error_2)
#print(error_2)
raise Exception(error_2)
return responce_decode
def bark(self, message):
""" Send message to iPhone if fails in clock-in, then log. """
url = 'https://api.day.app/' + self.bark_id + '/ClockInFalse/' + self.username
p = urllib.request.urlopen(url)
with open(self.log_path, 'a') as f:
f.write(self.get_date() + '\n')
f.write(message + '\n')
def get_info(self, html=None):
"""Get hitcard information, which is the old info with updated new time."""
if not html:
res = self.sess.get(base_url)
if res.status_code != 200:
error_3 = "{} get information failed, status code = {}".format(self.username, res.status_code)
self.bark(error_3)
#print(error_3)
raise Exception(error_3)
html = res.content.decode()
raw_json = json.loads(html)
return_dict = {}
for data in ('sfzx', 'tw', 'area', 'city', 'province', 'address', 'geo_api_info', 'sfcyglq', 'sfyzz', 'qtqk', 'askforleave'):
return_dict.update({data: raw_json['d']['info'][data]})
self.info = return_dict
return return_dict
def post(self):
""" Post the hitcard information."""
res = self.sess.post(save_url, data=self.info)
if res.status_code != 200:
error_4 = "{} post information failed, status code = {}.".format(self.username, res.status_code)
self.bark(error_4)
#print(error_4)
raise Exception(error_4)
return json.loads(res.text)
def main(self):
self.login()
time.sleep(0.5)
self.get_info()
time.sleep(0.5)
ret = self.post()
return ret
def clock_in_one_person(username, password, bark_id):
op = ClockIn(username, password, bark_id)
try:
ret = op.main()
if ret['e'] != 0:
error_5 = "fail in the end and the reason is {}.".format(ret['m'])
#print(error_5)
op.bark(error_5)
except Exception as e:
op.bark(e)
finally:
return 0
if __name__ == "__main__":
# username = sys.argv[1]
# password = sys.argv[2]
# bark_id = sys.argv[3]
username = "your username"
password = "your password"
bark_id = "your bark id"
clock_in_one_person(username, password, bark_id)
我们选用cron+shell脚本的方式来实现打卡程序的定时启动。
使用crontab -e
指令创建一个以当前用户运行的新cron任务,每个cron任务的格式如下:
<分钟> <小时> <日> <月> <星期> <命令or脚本路径>
cron任务中的操作符有*
,/
,-
和,
。*
代表取值范围内的所有数字,/
代表每过多少个数字,-
表示从起始到终止,,
表示散列数字。例如,每隔两天的上午8点到11点的第3和第15分钟执行任务可以写成3,15 8-11 */2 * * command
。
依此方式进行配置,最后使用crontab -l
查看已经存在的任务。
至此,实现了微信小程序的自动打卡🥂