×

一起来摆脱教务系统强制教评的痛苦

96
忠叔
2017.07.04 20:43* 字数 1334

文章的最后给出了使用方法,如果你没有编程经验的话,按照底下的教程直接拿来用就可以啦。

故事是这么开始的

每学习期末都会被教务系统的教学质量评价系统折腾的很惨,因为我必须完成所有科目的评价才能干别的事情。但是做这个评价又是一个非常痛苦的过程,每一个科目都要选一堆的项目,曾经因为选了十几门课,被教评狠狠地折腾到双手残废。


image.png

我曾在空间里看到有同学发过自动填充表单的脚本,大致是这样的

var divJs=frame.getElementById('divJs');
var items=divJs.querySelectorAll('select');
for(i=0;i<items.length;i++)
    items[i].value="1(完全同意)"

其实原理很简单,就是查询到所有评价项目的DOM,把它们的值逐一改成第一项就行了。运行这段脚本,页面上所有的评价就会自动填好,这时只要点击保存就可以了。
不过因为教务系统的网页是一个框架结构,教评的页面实际上是嵌在一个iframe里面的,所以我们要先让这个页面独立地在一个新标签中打开,才能去运行这段脚本。


image.png

不过聪明的你一定能发现其中的缺陷,我们在保存完之后,浏览器就会跳转到下一个科目的评价页面,这时候我们刚才运行的脚本已经被删除掉了。于是我们就得在每个页面把这个脚本粘贴到控制台再运行。在课程非常多的情况下,评价的效率仍有很大的提升空间。

第一次优化

这个时候我们正好可以利用教务系统这个框架结构的特点,我们在父页面运行脚本,让子页面在iframe跳转,脚本则可以一直保留在父页面中。我们对最初的脚本做一些改动,让父页面获取框架内的DOM(因为它们是同域的),再把代码封装到函数内,每跳到一个新页面执行一次函数就行了。

function autoFill() {
  var frame = document.getElementById('rightDiv').querySelector('iframe').contentWindow.document;
  var divJs = frame.getElementById('divJs');
  var items = divJs.querySelectorAll('select');
  for (i = 0; i < items.length; i++)
    items[i].value = "1(完全同意)"
}
autoFill();

image.png

这时,你一定能想到,既然都做到这一步了,干脆让点击保存按钮这个步骤也自动化咯,这样还省去了自己按按钮的麻烦。这时候,我们再加入一个间隔计时器,设定每2秒钟进行一次自动填充,并且保存。这样只要执行一次脚本,就可以哗哗哗地运行到底啦。

function autoFill() {
  var frame = document.getElementById('rightDiv').querySelector('iframe').contentWindow.document;
  var divJs = frame.getElementById('divJs');
  var items = divJs.querySelectorAll('select');
  for (i = 0; i < items.length; i++)
    items[i].value = "1(完全同意)"
  frame.getElementById('Button1').click();
}
setInterval(autoFill, 2000);

设定跳转的结束边界

很快我们就发现一个问题,当保存完最后一个科目的评价时,就应该提交了。但是由于计时器还在运行,这时候我们的框架还会不断地刷新,虽然这时你直接点击提交并且关闭页面就没事了,不过对于前端人员来说这样子太不优雅了。在这里加入一个判断方式:在进入一个新页面时,通过DOM获取课程代码,并保存在一个变量中。如果获取到的代码和上一次获取的代码是一样的,说明最后一个科目已经评价完成了,这时删除定时器就可以了。

var courseCode;
var timer;

function autoFill() {
  var frame = document.getElementById('rightDiv').querySelector('iframe').contentWindow.document;
  var divJs = frame.getElementById('divJs');
  var items = divJs.querySelectorAll('select');

  var newCourseCode=frame.getElementById('pjkc').value;
  if(newCourseCode==courseCode){
      clearInterval(timer);
      return;
  }
  courseCode=newCourseCode;

  for (i = 0; i < items.length; i++)
    items[i].value = "1(完全同意)"
  frame.getElementById('Button1').click();
}
timer=setInterval(autoFill, 2000);

优化轮询的方式

这里对计时器再进行一个改进,因为现在的执行间隔是2秒,在遇到网速慢的情况,或者函数从任务队列里弹出的时候正好DOM没有加载出来,那就会产生错误。在刚才的基础上,加入一个判断,如果获取不到课程代码的DOM(忽略获取课程代码和评价选项的微小的时间差),则跳过这次轮询,进入下一次就可以了。同时我们可以把轮询时间调短到1秒1次,这对服务器来说还是没有压力的。

var courseCode;
var timer;

function autoFill() {
  var frame = document.getElementById('rightDiv').querySelector('iframe').contentWindow.document;
  var divJs = frame.getElementById('divJs');
  var items = divJs.querySelectorAll('select');

  if(!frame.getElementById('pjkc'))
      return false;

  var newCourseCode=frame.getElementById('pjkc').value;
  if(newCourseCode==courseCode){
      clearInterval(timer);
      console.log('评价完成');
      return true;
  }
  courseCode=newCourseCode;

  for (i = 0; i < items.length; i++)
    items[i].value = "1(完全同意)"
  frame.getElementById('Button1').click();
}
timer=setInterval(autoFill, 1000);

收尾

最后,把我们的代码重新整理一下,封装到一个闭包里面,避免污染了全局作用域。一个用起来超爽的自动教评程序就完成了。

(function() {
  var courseCode;
  var timer;

  var autoFill=function() {
    var frame = document.getElementById('rightDiv').querySelector('iframe').contentWindow.document;
    var divJs = frame.getElementById('divJs');
    var items = divJs.querySelectorAll('select');

    if (!frame.getElementById('pjkc'))
      return false;

    var newCourseCode = frame.getElementById('pjkc').value;
    if (newCourseCode == courseCode) {
      clearInterval(timer);
      console.log('评价完成');
      return true;
    }
    courseCode = newCourseCode;

    for (i = 0; i < items.length; i++)
      items[i].value = "1(完全同意)"
    frame.getElementById('Button1').click();
  }
  timer = setInterval(autoFill, 1000);
})();

测试起来,速度堪比开车。本来想写成chrome插件的,不过这种一次性的东西,装上还得卸掉也麻烦,就直接附上脚本的运行方式,不学编程的同学也可以拿来用喔。


附:大众版使用方法

首先你要复制下面这段代码

(function() {
  var courseCode;
  var timer;

  var autoFill=function() {
    var frame = document.getElementById('rightDiv').querySelector('iframe').contentWindow.document;
    var divJs = frame.getElementById('divJs');
    var items = divJs.querySelectorAll('select');

    if (!frame.getElementById('pjkc'))
      return false;

    var newCourseCode = frame.getElementById('pjkc').value;
    if (newCourseCode == courseCode) {
      clearInterval(timer);
      console.log('评价完成');
      return true;
    }
    courseCode = newCourseCode;

    for (i = 0; i < items.length; i++)
      items[i].value = "1(完全同意)"
    frame.getElementById('Button1').click();
  }
  timer = setInterval(autoFill, 1000);
})();

打开教务系统,进入教学评价页面


image.png

打开浏览器的控制台

多数浏览器的控制台是按F12调出,如果你的浏览器不得行的话,在菜单里找一找有没有开发者工具。打开面板后,选择Console,就是控制台了。


image.png

粘贴代码回车,10秒搞定,这下就可以放飞自我地查成绩了!

搞事情
Web note ad 1