如何优雅地在北邮打卡、出校
开源代码见 Github OhYee/bupt-scripts
由于疫情原因,每天都需要准时打卡上报数据,且出校需要申请。
尽管本质上该政策没有任何问题,但是对于大部分身体处于健康状态的人来说,每天要做的只是重复性地填写上一天已经填写过的东西。特别是请假出校,甚至连辅导员、手机号都需要每次重新填写。
尽管填写这些东西并不需要花费特别多的时间,但是仍然需要在各种连贯性的工作时,去继续执行这件事。对于这些重复性的工作,应该交由代码来解决。只有某天自己真的发烧时,再关闭脚本修改参数。
尽管目前已有相应的打卡脚本,但是不少都使用的 selenium。从结果上看,这些代码可用,但是从过程上看,这些代码极其不优雅。首先是 selenium 本身是模拟浏览器操作,会有额外的性能损耗。其次是 selenium 需要安装浏览器及其对应版本的浏览器驱动。本身一个非常简单的接口功能却需要安装很多实际上用不到的东西,非常浪费资源。
因此这里采用抓包找接口的形式来实现
打卡
打卡登录请求
首先在电脑端的微信打开疫情防控通填报页面,得到链接https://app.bupt.edu.cn/ncov/wap/default/index
。
这时如果为登录,会跳转到https://app.bupt.edu.cn/backend/default/login?redirect=%2F
请求登录,测试可知这里账号是学号,密码为服务平台密码(默认为身份证后 8 位)
抓包可知,登录为一个 POST 请求,参数为账户和密码
https://app.bupt.edu.cn/uc/wap/login/check
类型
POST
参数
参数名 | 类型 | 解释 |
---|---|---|
username |
字符串 | 账号(学号) |
password |
字符串 | 密码(默认身份证后 8 位) |
返回值为 JSON 格式,其中e
字段为状态码,如果为0
说明没有问题,否则则需要查看m
字段的错误信息
打卡请求
登陆成功后,即可进入打卡页面。由于一天只能打卡一次,因此要测试需要从页面本身着手。
查看页面的源码,可以发现该页面使用 Vue 实现,且未经过混淆,因此可以直接查看按钮逻辑。可以看到打卡按钮调用 Vue 的confirm()
方法,并通过添加wapcf-btn-qx
来实现禁止点击样式
<div class="footers"> <a @click="confirm()" :class="{'wapcf-btn-qx': hasFlag == 1}" >提交信息(Submit)</a> </div>
confirm()
方法根据 Vue 的成员变量hasFlag
来判断状态,如果打卡成功,则其为1
。因此,如果想要调试,需要想办法把它重置为0
confirm() { if(this.hasFlag == 1) { wapalert('每天只能填报一次,你已提交过(Daily Report can only be submitted once a day. You have already submitted)','确认(Confirm)'); return false; } if(!this.valid(this.info)) { return false; } wapconfirm('每天只能填报一次,请确认信息是否全部正确?(Daily Report can only be submitted once a day. Please confirm that all the information is correct.)', '确认<br>Submit', '再看看<br>Check again', function () { vm.save(); }); },
尽管该页面关闭了调试模式,无法直接使用 Vue Devtools 插件来编辑,但是从源码可以看出,Vue 对象实例被赋值给了vm
变量
var vm = new Vue({ el: '.form-detail2', ... });
那么,在控制台直接设置vm._data.hasFlag=0
,即可重置其成员变量。如图,可以看到按钮已经可以点击
接下来就可以抓包了。
打卡请求本身没有额外的验证,但是需要提交的参数非常多,不过基本都可以在页面本身就有的内容获取。
在代码中,有两部分重要内容def
和oldInfo
,前者为全局变量,后者为 Vue 的成员变量。不过在爬虫里直接使用正则表达式提取即可。
这两个变量中,def
是当前表单生成的新数据(如当前的表单提交 ID),oldInfo
则是上一次提交的值(前一天的数据)。只需要结合这两者的内容,既可以作为当日的新提交。
经过对比,可以得知需要使用新表单的数据只有date
、created
、id
三项,其余的都可以从oldInfo
获取(如果不存在则留空(使用oldInfo.get("date","")
可以在检索字典时,获取默认值))
涉及的字段如下:
oldKeys = [ "ismoved", "jhfjrq", "jhfjjtgj", "jhfjhbcc", "sfxk", "xkqq", "szgj", "szcs", "zgfxdq", "mjry", "csmjry", "uid", "tw", "sfcxtz", "sfyyjc", "jcjgqr", "jcjg", "sfjcbh", "sfcxzysx", "qksm", "remark", "address", "area", "province", "city", "geo_api_info", "sfzx", "sfjcwhry", "sfcyglq", "gllx", "glksrq", "jcbhlx", "jcbhrq", "sftjwh", "sftjhb", "fxyy", "bztcyy", "fjsj", "sfjchbry", "sfjcqz", "jcqzrq", "jcwhryfs", "jchbryfs", "xjzd", "sfsfbh", "jhfjsftjwh", "jhfjsftjhb", "szsqsfybl", "sfygtjzzfj", "gtjzzfjsj", "sfsqhzjkk", "sqhzjkkys", "created_uid", "gwszdd", "sfyqjzgc", "jrsfqzys", "jrsfqzfy" ] defaultKeys = [ "date", "created", "id", ]
将拼接好的数据通过 POST 方式发送至https://app.bupt.edu.cn/ncov/wap/default/save
即可
同登录接口,这里返回的也是一个 JSON 数据,只需要判断e
是否为0
即可
打卡开源
代码开源与 Github,使用 Python 实现
请假
请假登录
请假与打卡使用的是同一个账号系统,但是登录跳转的页面不同。
登录会跳转至https://auth.bupt.edu.cn/authserver/login
需要特别注意的是,这个页面为了防止 CSRF 每次都会生成一个不同的 LT 值,因此需要先使用 GET 请求获取该值(可以使用正则表达式<input type="hidden" name="lt" value="(.*)" />
获取),再请求对应的登录接口
https://auth.bupt.edu.cn/authserver/login?service=https%3A%2F%2Fme.bupt.edu.cn%2Fsite%2Flogin%2Fcas-login
类型
POST
参数
参数名 | 类型 | 解释 |
---|---|---|
username |
字符串 | 账号(学号) |
password |
字符串 | 密码(默认身份证后 8 位) |
lt |
字符串 | 需要从页面中获取 |
execution |
字符串 | 固定为e1s1 |
_eventId |
字符串 | 固定为submit |
rmShown |
整数 | 固定为1 |
请假请求
登录成功后,即可在https://service.bupt.edu.cn/v2/matter/start?id=578
页面进行申请
在请求之前,可以访问https://service.bupt.edu.cn/site/user/get-name
获取用户信息,一方面可以获取用户的学院信息,另一方面也是检查登录是否成功
https://service.bupt.edu.cn/site/user/get-name
类型
GET