学校要求每天都要填疫情相关的情况统计表,每天都需要去那边填一下,而且时间有严格的要求,早上很早就截止了。手动提交实属麻烦,于是开始想方法做自动化。
API
首先要实现自动填报,自然是要抓到API。填报的入口在微信,但是在登录后未见操作另外再调用微信进行鉴权。
通过抓包发现进入页面后和页面对应后端进行通信的鉴权是通过AES加密的两个参数实现的,这两个参数直接附在了URL上,这意味着我们很轻松就能实现自动填报。
由于开发脚本当天已经填报过了,所以直接JS里找到提交方法提交,用Burp截包提取到提交的参数。很意外的是这个提交接口是没有任何鉴权的,那自动填报脚本就更好做了。
有了抓包的基本信息后面的问题就很好解决。
脚本
数据是一个表单序列化成了JSON,常规操作,把表单序列化之后的内容提取出来,放到JSON文件里,后续填报的时候直接反序列化这一份数据,修改好之后提交过去就行了。
考虑到表单里面含有日期参数,引入dayjs根据参数的形态构造一个日期的字符串,填入JSON内日期字符串所在的位置,就能够实现动态改变数据里的日期。
剩下的操作就是node-cron + axios提交就行了,API也没有CORS限制,安全方面很松,加了CORS限制也无妨,走cors-anywhere等就能解决问题。
坑
第一天测试这个失败了,然后我被挂在了未及时填报的名单上。后面追查原因发现服务器接受的参数不一般,JSON数据要先使用JSON.stringify序列化成字符串之后再进行提交。
一开始我也很奇怪为什么会出现这样的错误,如果数据提交过去了,对于Java后端来说做不做这一步操作其实都是一样的,发送过去的东西本身就不会是一个没有序列化的数据。
这个坑其实是出在axios上,这个接口不是POST方法,而是GET方法,在用GET方法发请求的时候,params里的对象是没有办法正确传递过去的,我的代码也没有预先设置好序列化的东西。
从API来看它这个表单参数的体现是JSON序列化后的字符串,所以我先把它序列化好就能正常提交。
增强
脚本姑且到这里是能用了,但是缺少一个提醒,不知道每天填报是不是做好了,而且也缺少一个容错的措施,万一网络波动了没有填报上,那么后续最好还要重试。
重试这个简单,在规定时间范围内执行多次cron,如果当天没有成功就持续重试,成功了就不用再重试了。
提醒这方面主要是通过邮件,短信的话需要一定费用,我没有开通短信包所以没有选用短信。邮件使用node-mailer对接SMTP就能直接发邮件,我选用的是我自己的阿里企业邮SMTP,成功和失败都发通知,就解决了通知方面的问题。
每天看到通知就能知道是不是填成功了,不至于无感知还要人工确认,每天人工确认不如自己手动提交来得稳。所以提醒还是很重要的。
做好了这一切就上线运行了,至今几天都运转稳定,感觉良好。
代码
代码基于MIT协议开源,附表单模板。API地址出于安全原因不提供,如果你也是同校的同学,请自行抓包。这个代码还有改进的控件,比如抽出SMTP配置和模板到文件里面,但是不太想改进了,毕竟这是一个临时工具,不值得投入那么多。
具体的用法请阅读代码自行理解。
1 | const axios = require('axios'); |
data.json(填报信息模板):
Tips:括号里的内容需要你自行填写
1 | [{ |
package.json
1 | { |
建议使用pm2运行。
更新:method修改
接口从GET转成了POST,GET会返回405,需要调整调用方式。
axios的POST需要规避相关的坑,对于升级后端,提交的参数需要进行一定调整,有在使用该脚本的最好抓个包把参数也更新一下。
特别提醒
填报模板基于完全正常状态制作,如果你的情况特殊,请如实手动填报表格。
这里提供的代码不保证稳定性,如果你的填报出现了问题请自担责任,与我无关。