【多所学校均适用】图书馆空间预约系统自动预约脚本 | Java | 座位预约、研讨间预约;抢座快人一步
【复旦大学研讨间 复旦大学座位预约 华东师范大学座位预约系统 六盘水师范学院座位预约系统 西南交通大学座位预约系统 新疆农业大学座位预约系统】 根据盛卡恩官网介绍,上述高校均使用了他们的座位预约系统。其实还有很多其他学校也是,可以看看你们学校的座位预约系统是是不是下面这样的:
复旦、华师、西交等图书馆座位自动预约脚本支持多所高校 或者可以简单抓包你们预约的请求,看是不是有的请求有"https://www.skalibrary.com"。 如果满足上面条件的话,基本上确定是盛卡恩系统了。
基本的功能都满足了:
说一下进阶的功能:
还有更进一步(这个不提供接口,因为比较冒险,不过肯定可以就是了,感兴趣的可以自己试试):
请勿滥用,仅供交流学习~,使用时请遵守学校相关的规章制度,管理条例!
脚本地址:https://github.com/quarkape/ecnu-lib-auto-book.git
接下来开始抓包分析预约过程(以华东师范大学图书馆预约系统为例):
老规矩,还是先抓包,用到了fiddler。具体来说就是电脑和手机连接wifi并保证处于同一局域网下。然后手机修改wifi的配置,手动配置主机地址和端口号,由fiddler代{过}{滤}理即可开始抓包。 亲测,在电脑上打开公众号网页没用,会检测到非手机端微信,所以只能用此方法。 好了,开始抓包。我一般都是先在手机上把关键的操作做一遍,然后一条一条的分析每个请求的作用。
第一个请求,从url可以看到请求函数为login,可以大胆推断这个请求就是用户登录。因此简单分析请求头、请求体和请求方法即可。这个不难,代码如下:
// 用户登录
public static HashMap<String, String> login() throws IOException {
HashMap<String, String> map = new HashMap<>();
map.put("status", "0");
JSONObject obj = requestPost(BASE_URL + "/login", "from=mobile&password=" + PASSWORD + "&username=" + USERNAME);
if (obj.getInteger("status") == 1) {
JSONObject infoObj = obj.getJSONObject("data").getJSONObject("list");
map.replace("status", "1");
map.put("name", infoObj.getString("name"));
map.put("card", infoObj.getString("card"));
map.put("deptName", infoObj.getString("deptName"));
map.put("gender", infoObj.getString("gender"));
map.put("roleName", infoObj.getString("roleName"));
map.put("accessToken", obj.getJSONObject("data").getJSONObject("_hash_").getString("access_token"));
}
return map;
}
注意,上述代码返回hashmap,是因为里面的参数在最后的预约请求中要用到。
第二个请求,请求函数是addUser,请求体里面也包含了学号等信息,但是域名不是学校的了,是一个第三方的域名,我查了一下,应该是上海盛卡恩智能系统有限公司。我猜测这个请求可能与闸机有关?没有测试过这个请求到底有没有实际作用,但是保险起见还是必须要加上的。因此,第二段代码为:
// skalibrary添加用户信息
public static Boolean addUser(String name, String card, String deptName, String gender, String roleName) throws IOException {
String paramsStr = "openid=" + OPENID + "&username=" + USERNAME + "&password=" + PASSWORD + "&name=" + name + "&card=" + card + "&deptName=" + deptName + "&gender=" + gender + "&roleName=" + roleName + "&school=" + SCHOOL + "&schoolName=" + SCHOOL_NAME;
JSONObject obj = requestPost(SKALIB_URL + "/addUser", paramsStr);
return obj.getBoolean("status");
}
// 获取可预约时间段
// date : 预约日期 : 2023-03-05
public static HashMap<String, String> getViableTime(String areaCode, String date) throws IOException {
HashMap<String, String> map = new HashMap<>();
map.put("status", "0");
JSONObject obj = requestGet(BASE_URL + "/space_time_buckets?area=" + areaCode + "&day=" + date);
if (obj.getInteger("status") == 1) {
map.replace("status", "1");
String segment = obj.getJSONObject("data").getJSONArray("list").getJSONObject(0).getString("id");
String spaceId = obj.getJSONObject("data").getJSONArray("list").getJSONObject(0).getString("spaceId");
map.put("segment", segment);
map.put("spaceId", spaceId);
}
return map;
}
// 预约座位
// type : 操作类型 : 1 : 预约座位
// setId : 座位id : 6056
public static HashMap<String, String> grabSeat(String accessToken, String type, String segment, String seatId) throws IOException {
String paramStr = "access_token=" + accessToken + "&userid=" + USERNAME + "&type=" + type + "&id=" + seatId + "&segment=" + segment;
JSONObject obj = requestPost(BASE_URL + "/spaces/" + seatId + "/book", paramStr);
HashMap<String, String> map = new HashMap<>();
map.put("status", "0");
if (obj.getInteger("status") == 1 && obj.getString("msg").indexOf("预约成功") != -1) {
map.replace("status", "1");
}
map.put("msg", obj.getString("msg"));
return map;
}
// 自动预约
public static void autoGrabSeat() throws Exception {
// 获取明天日期
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) + 1);
String tomorrow = formatter.format(calendar.getTime());
String content = "<div>预约位置:xxxx</div><div>位置id:" + SEAT_ID + "</div><div>预约日期:" + tomorrow + "</div>";
// 开始预约
// 先登出当前用户
Boolean hasLogOut = removeUser();
HashMap<String, String> map = login();
if (map.get("status") == "0") {
content = "<div>预约结果:预约失败</div>" + content + "<div>失败原因:初始登录失败</div>";
SendEmailUtil.sendEmail(EMAIL, content);
return;
}
Boolean addUser = addUser(map.get("name"), map.get("card"), map.get("deptName"), map.get("gender"), map.get("roleName"));
if (!addUser) {
content = "<div>预约结果:预约失败</div>" + content + "<div>失败原因:向skalibrary写入用户信息失败</div>";
SendEmailUtil.sendEmail(EMAIL, content);
return;
}
HashMap<String, String> map1 = getViableTime("40", tomorrow);
if (map1.get("status") == "0") {
content = "<div>预约结果:预约失败</div>" + content + "<div>失败原因:获取segement参数的过程中失败</div>";
SendEmailUtil.sendEmail(EMAIL, content);
return;
}
// 默认type为1
HashMap<String, String> res = grabSeat(map.get("accessToken"), TYPE, map1.get("segment"), SEAT_ID);
if (res.get("status") == "1") {
content = "预约结果:预约成功!" + content;
} else {
content = "<div>预约结果:预约失败</div>" + content + "<div>失败原因:" + res.get("msg") + "</div>";
SendEmailUtil.sendEmail(EMAIL, content);
return;
}
SendEmailUtil.sendEmail(EMAIL, "<div>预约结果:预约成功!</div>" + content + "<div>莫等闲,白了少年头,空悲切!</div>");
}
在上述代码中,我还加入了发送邮件的功能。