He110 发表于 2017-6-9 13:55

JS 实现正方教务系统一键评教

本帖最后由 He110 于 2017-6-9 13:57 编辑

烦透的正方,非得找麻烦。
忽然想到一位破解界前辈说过的,很多时候,破解是为了抵制那些垃圾产品经理设计的垃圾需求,现在深有同感


评教有什么用?集体评这个老师不好就能不给他教了吗?不,还是一样,该怎么样就怎么样,存在的唯一理由,就是为了给领导看


初衷


本教程并不是为了破解而破解,纯粹属于最近心情不好,正方恰巧撞枪口罢了,以前直接使用火狐评教,直接使用 tab 键切换到下一个下拉框,可以节省很多时间,而且不容易被查出来,而最近挺烦躁的,所以也不想再这么搞下去了,故编写了一个脚本用于一键评教

原理


其实有两种方法:第一种就是改包发包到服务器,直接越过正方的评教界面,但是容易被查出来,并且数据包修改不好修改,一个不好容易被发现,并且不适合零基础的人群使用,故暂且不提


第二种便是模拟人为操作的过程,原理其实很简单,稍微分析一下,评教需要做的,就是修改下拉框的值,然后点击一个按钮,循环这个过程,直到所有的课程评教完成即可,那么首先要解决的是评教次数的问题,在正方的评教系统中有一个下拉框是用于显示评教涉及的课程的,包括了评教的和未评教的,故而可以使用 JS 脚本直接获取这个下拉框的下拉选项数,作为循环次数,也就是:


1
var li = document.querySelectorAll("ul.nav>li.top")[3].querySelectorAll("ul.sub>li").length;
这句语句就是获取循环次数,也就是课程数的,每次循环的时候将 li 减一即可接下来是获取评教中每个课程的所有的下拉框,原本以为会是 AJAX,那样就比较复杂了,没想到是 iframe 窗体,容易多了,只需要编写一套使用每个课程评教界面的 DOM 操作就行了,直接上代码好了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 获取课程所有的下拉框
var selects = iframe.contentDocument.querySelectorAll('table.datelist>tbody>tr>td>select');
// 将下拉框的 Index 全部置为 1 也就是评价为 B
for (var i = 0; i < selects.length; i++) {
    // 索引为 1 表示为 B,可选值为:0: A,1: B,2: C,3: D...具体看教务系统给多少个等级
    selects.selectedIndex = 1
}
// 取一个随机数 index,第 index 个下拉框评价等级修改为 C,避免全部选项相同无法提交
var index = Math.round(Math.random() * (selects.length - 1));
selects.selectedIndex = 2;
// 写评语,可以改为使用随机值的,我比较懒就使用了固定的
iframe.contentDocument.getElementById("pjxx").value = '老师很认真负责';
// 模拟点击保存按钮
iframe.contentDocument.getElementById("Button1").click();


完整的代码


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
// 获取相关资源
var iframe = document.querySelector('iframe');
// 总共需要评教的课程数
var li = document.querySelectorAll("ul.nav>li.top")[3].querySelectorAll("ul.sub>li").length;
// 信号量/许可证
status = false;
// 评教函数定义
function pj() {
    // 判断是否正在执行评教脚本,是则退出,因为重复执行有可能会出 BUG,有的课程评教不全,也就是只修改了部分下拉框,就被提交了
    if (status) {
      // 结束脚本
      return;
    }
    // 修改标志位,相当于多线程许可证,或者是信号量一般,让脚步互斥执行
    status = true;
    // 判断是否需要评教,不需要则弹出提示框表示评教完成
    if (li == 0) {
      iframe.setAttribute('onload', "javascript:dyniframesize('iframeautoheight');");
      // 模拟点击提交按钮
      iframe.contentDocument.getElementById("Button2").click();
      // 提示完成评教
      alert("done");
      // 结束脚本
      return;
    }
    // 获取课程所有的下拉框
    var selects = iframe.contentDocument.querySelectorAll('table.datelist>tbody>tr>td>select');
    // 将下拉框的 Index 全部置为 1 也就是评价为 B
    for (var i = 0; i < selects.length; i++) {
      // 索引为 1 表示为 B,可选值为:0: A,1: B,2: C,3: D...具体看教务系统给多少个等级
      selects.selectedIndex = 1
    }
    // 取一个随机数 index,第 index 个下拉框评价等级修改为 C,避免全部选项相同无法提交
    var index = Math.round(Math.random() * (selects.length - 1));
    // 修改下拉框,避免所有下拉框的值都相同导致无法保存
    selects.selectedIndex = 2;
    // 写评语,可以改为使用随机值的,我比较懒就使用了固定的
    iframe.contentDocument.getElementById("pjxx").value = '老师很认真负责';
    // 模拟点击保存按钮
    iframe.contentDocument.getElementById("Button1").click();
    // 循环变量 -1
    --li;
    // 设置脚本运行结束,可以再次执行脚本
    status = false;
}
iframe.setAttribute('onload', "javascript:dyniframesize('iframeautoheight'); pj();");

// 开始评教
pj();
直接打开控制台(按 F12 或者点击开发者工具,选择控制台),将完整代码粘贴进去,点击执行即可,Chrome 下测试成功,欢迎反馈 BUG,目前已知的 BUG 如下:
[*]如果评教过程出错,还是会继续执行,缺少检错机制,但是出现错误的情况极少,故不继续添加检错机制,避免代码过于臃肿
[*]评语每次都一样,容易被查出来,可以使用随机语录,制作中…


总结

原理容易想到,但是在实现过程也是碰了不少的坑,主要还是对 JS 不了解,以后可能出个 PHP 版本的,毕竟我还自认是个 PHPer~PHP 是最好的语言~

孟坤软件 发表于 2017-6-9 15:02

这个不错!可惜我们的教务系统是 强智 的{:301_1005:}

He110 发表于 2018-6-17 11:16

Hakon 发表于 2018-6-15 23:55
……总觉得这样做好像既背离了评教的初衷也背离了自动化的初衷。呃,只是技术层面以外的感想。

评教目前没有任何意义,完全是为了评教而评教,就算全班给老师差评又怎么样,还是继续是他教,那评教有什么意义?一不扣工资二不调整岗位的,这种事不自动化,还等着认真写?让别人糟蹋你花了 N 久填的表?

dj1149 发表于 2017-6-9 14:08

表示青苹果也是一样恶心

tzxinqing 发表于 2017-6-9 14:09

不明觉厉,支持一下

心飞扬 发表于 2017-6-9 14:44

支持一下

6767 发表于 2017-6-9 16:01

这个巨坑。。。我们学校的垃圾系统

He110 发表于 2017-6-9 19:12

dj1149 发表于 2017-6-9 14:08
表示青苹果也是一样恶心

表示没用过

He110 发表于 2017-6-9 19:16

孟坤软件 发表于 2017-6-9 15:02
这个不错!可惜我们的教务系统是 强智 的

思路可以试试,按着代码改,也许能成功

无影寒冬 发表于 2017-7-1 09:20

不明觉厉,每次我都是手动的。

ncepu2016 发表于 2017-7-6 18:16

游客有什么办法进去
页: [1] 2
查看完整版本: JS 实现正方教务系统一键评教