写了一段简短的上大自动查成绩脚本(支持微信推送)

前言

每逢期末出分的时候,我宝一天能进n次查分网站,为的就是看有没有新出的成绩。然而这样子劳民伤财,费时费力(挂vpn+登校园网+查看),于是我试着扒了下网站的源码,参考网上类似的教程写了一段简短的js运行脚本,以方便出分时自动查看。也算是增加一点经验hh

特性

  • 自动定时获取某学期当前最新成绩,可自定义

    • 学期
    • 刷新间隔
  • 支持成绩提醒,可自定义

    • 每次刷新后提醒(不推荐,仅作测试和debug用)
    • 成绩有变动时提醒

    提醒方式包括

    • 浏览器自带提醒(推荐Chrome)
    • 微信提醒

脚本代码

脚本代码见下,具体使用方法和解析见后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
* @Author: Baokker
* @Date: 2022-09-30 19:10:10
* @LastEditors: Baokker
*/

// 获取相关设置
let timeout = Number(prompt('输入查询成绩的时间间隔(请不要太短,以免被认为是攻击)', '15'));
let academicTerm = prompt('输入查询成绩的学期(格式:4位年份+季节,例如:2022夏)', '2022夏');
let whetherShowContinuously = prompt('是否开启持续提示(默认为否,填任意其他内容即为是)(微信提醒时不建议开启)', '否');
let whetherShowExplorerMessage = prompt('是否开启浏览器消息提示(默认为否,填任意其他内容即为是)', '否');
let whetherShowWechatMessage = prompt('是否开启微信提示(需登录息知(https://xz.qqoq.net/#/index)获取key)(默认为是,填任意其他内容即为否)', '是');
let key;
if (whetherShowWechatMessage == '是') {
key = prompt('输入息知里对应的key');
}

// 初始化变量
let semesterDic = { '秋': 1, '冬': 2, '春': 3, '夏': 5 };
let academicTermID = (Number(academicTerm.substring(0, 4)) - 1) * 10 + semesterDic[academicTerm.substring(academicTerm.length - 1, academicTerm.length)];

count = 0; // 已刷新次数
current = location.href; // 当前页面链接

let gradeTable = [];
let oldGradeTable = [];

// 设置定时
if (timeout > 0) {
setTimeout('reload()', 1000 * timeout);
}
else {
location.replace(current);
}

// 自动重载页面
function reload() {
// 刷新页面,更新刷新次数
setTimeout('reload()', 1000 * timeout);
count++;
console.log(`每${timeout}秒自动刷新,刷新次数:${count}`);

// 发送ajax请求,获取最新成绩
$.ajax({
type: "POST",
url: "/StudentPortal/CtrlScoreQuery",
data: { academicTermID: academicTermID },
cache: false,
success: function (gradeResponse) {
oldGradeTable = gradeTable;
let gradeHTML = gradeResponse;
let placeholder = document.createElement('div');
placeholder.innerHTML = gradeHTML;
let gradeTableHTML = placeholder.getElementsByClassName("tbllist")[0];
for (var i = 0, rows = gradeTableHTML.rows.length; i < rows; i++) {
for (var j = 0, cells = gradeTableHTML.rows[i].cells.length; j < cells; j++) {
if (!gradeTable[i]) {
gradeTable[i] = new Array();
}
gradeTable[i][j] = gradeTableHTML.rows[i].cells[j].innerHTML.replace(/\s/g, "").replace(/&nbsp/g, "");
}
}
}
});

// 调用方法,检查是否满足条件
checkInfo();
}

// 检查是否满足条件 满足时开启通知提示
// 可根据实际情况调整该部分判断内容
function checkInfo() {
if (oldGradeTable.length == 0) {
oldGradeTable = gradeTable;
}
else if (oldGradeTable != gradeTable) {
oldGradeTable = gradeTable;
notify();
}
else {
if (whetherShowContinuously != '否') {
notify();
}
}
}

function arr2Str(objarr) {
var arrLen = objarr.length;
var row = "[";
for (var i = 2; i < arrLen; i++) { // skip unnecessary parts
row += "[";
for (var j = 0; j < objarr[i].length; j++) {
row += objarr[i][j];
if (j < objarr[i].length - 1) {
row += ",";
}
}
row += "]";
if (i < arrLen - 1) {
row += ",";
}
}
row += "]";
return row;
}

// 通知提示
function notify() {
// 判断是否开启了浏览器通知,若开启成功,则可以在自动刷新满足条件后正确发送通知
// 可以打开 chrome://settings/content/notifications 设置“允许发送通知”链接
let body = arr2Str(gradeTable);

if (whetherShowExplorerMessage != "否") {
if (window.Notification && Notification.permission !== "denied") {
Notification.requestPermission(function (status) {
var n = new Notification(`有成绩更新!`, { body: body });
});
}
}

// 微信提示
if (whetherShowWechatMessage == '是') {
sendWechatMessage(key, "有成绩更新!", body);
}
}

// 息知发送微信通知
function sendWechatMessage(key, title, message) {
var httpRequest = new XMLHttpRequest(); // 第一步:建立所需的对象
httpRequest.open('GET', `https://xizhi.qqoq.net/${key}.send?title=${title}&content=${message}`, true); // 第二步:打开连接
httpRequest.send(); // 第三步:发送请求 将请求参数写在URL中
}

使用方法

推荐浏览器:Chrome

  1. 登录到上海大学教务管理系统(需要校园网或连接VPN(说明))
    image-20221002104710334
    image-20221002104813418

  2. F12打开开发者工具,找到Console控制台,将上文的脚本代码复制粘贴至此,然后enter换行开始运行

    image-20221002104956085

  3. 输入自定义设置
    时间间隔

    image-20221002105018333

    学期名
    image-20221002105043265
    默认只在成绩更新时发送通知,这里为演示效果,将持续提醒设为了

    image-20221002105110857
    浏览器提示,当你经常使用电脑时,可以借此接收提醒

    image-20221002105136157

    微信通知(建议开启)
    image-20221002105243965
    微信提示调用了息知的接口,需登录其网站,获取对应Key
    image-20221002105333025
    image-20221002105459927
    复制粘贴到输入框中
    image-20221002105534692

  4. 完成后,保持该窗口不关闭,即可自动开始运行
    浏览器提醒样式

    image-20221002105746998
    微信提醒样式(需关注息知公众号)

    image-20221002110116949 image-20221002110127136

原理剖析

shu教务系统

仅做技术分享,莫拿来当攻击手段哈~

教务系统的技术栈比较老,还是jQuery+Ajax,样式就用基础的css(我济都用上element UI了~)

登录这一块本来也想做做,但是对html的基础知识还是不够了解,因而作罢。本质上说就是设定表单提交的url,然后对password进行加密,加上username直接传过去,成功就跳转页面。

查分这一块特别简单,抓了一下包发现,网页上面的查询按钮,对应调用的就是ScoreQuery函数,该函数发送了一个ajax的post请求,返回的response即为下面成绩一栏的html源码,然后通过指定id,直接把这段html赋给了网页…

image-20221002110609607

image-20221002110839015

image-20221002115820000

Post请求里带的AcademicTermID,搜索后可发现,即为对应的学期名,并且存在映射关系,如

{ '秋': 1, '冬': 2, '春': 3, '夏': 5 }

image-20221002115848013

微信提醒

微信提醒调用了息知的api接口(之前还看过server酱的接口,然鹅现在看貌似每天只能免费五条)

扫描二维码后,通过get或post请求发送如下内容

1
https://xizhi.qqoq.net/{key}.send?title=标题&content=内容

即可

bug

异步

js与其他语言相比,最大的特点在于异步,例如ajax发送了post请求获得成绩,但是在发送请求的那一刻开始,尽管还没有接收到结果,但是代码已经往下执行了,所以当到checkInfo的时候,可能并未获取最新的成绩。我修改了一些逻辑,以掩饰这个bug()

参考链接

https://juejin.cn/post/7043325422796439560

https://github.com/panghaibin/shu-web-js


写了一段简短的上大自动查成绩脚本(支持微信推送)
http://baokker.github.io/2022/10/01/写了一段简短的上大自动查成绩脚本(支持微信推送)/
作者
Baokker
发布于
2022年10月1日
更新于
2022年10月2日
许可协议