MENU

锐格答题助手,OpenLab 自动获取填充答案

2018 年 07 月 02 日 • 技术流

锐格 OpenLab 是一款我们之前在用的在线实训系统,有自动批改作业的功能。一年前的期末,为了缓解作业压力,我编写了这个油猴脚本(适用于 Greasemonkey 的用户脚本),能够支持各种已知题型,自动获取答案,解析答案,填充答案,最后提交。鉴于“锐格”在我们学校似乎已经不使用了,特在本文分享思路以及源代码。

实际上,锐格 OpenLab 本身是有查看答案功能的。不过它设计为,如果没有正确作答就查看答案,该题作废,计为零分;那我们如果已经正确作答,就没有必要再去查看答案了,手动滑稽。“锐格”的疏忽之处在于,只在入口处应用了这套规则,而实际的答案页面并不受到限制。于是这个脚本的核心部分就有了,去获取那个答案页面的内容,就能得到参考答案了。

之后的解析、填充和提交不必多言,只要会用 JavaScript 操作 HTML DOM 就不难写出。需要指明的是,对于改错题和编程题,填充答案是有技巧的。你不能直接填充到什么<input>或者<textarea>元素里。锐格 OpenLab 的代码编辑器没那么简单。我花了好一番工夫,才在网页源码里找到了直接好用的接口:Coder.set(answer)

在此把“锐格答题助手”脚本全部源代码分享如下(隐去了 OpenLab 的域名):

// ==UserScript==
// @name        锐格答题助手
// @namespace   xw.rgdt
// @include     http://example.com/studentExercise/index?currentClassId=*
// @run-at      document-end
// @version     1.4
// @grant       none
// ==/UserScript==

main();

function main(obj){ //事件调用会传入 obj
    setTimeout(function(){
        if(document.getElementById("lookKey")){
            //if(!obj) document.getElementById("treeDemo").addEventListener("click",main);
            if(!obj) window.addEventListener("hashchange",main);
            mainFunc();
        }else{
            main();
        }
    }, obj?300:800);
}

function mainFunc(){
    if(!document.getElementById("type_sub")){
        dropErr("未能识别题目类型!");
        return false;
    }
    if(!document.getElementById("lookKey")){
        dropErr("未能获取题目关键信息来查看答案!");
        return false;
    }
    var type = document.getElementById("type_sub").innerHTML;
    var para = document.getElementById("lookKey").href.split(',');
    var id = para[1];
    var section_id = para[2];
    section_id = section_id.substr(0, section_id.length-1);

    var xmlHttp = new XMLHttpRequest();
    var text = "";
    xmlHttp.onreadystatechange = function() {
        if (xmlHttp.readyState == 4){
            if(xmlHttp.status == 200){
                text = xmlHttp.responseText;
            }else{
                dropErr("获取答案时发生错误!HTTP 状态码:"+xmlHttp.status);
                return false;
            }
        }
    };
    xmlHttp.open("GET", "/studentHome/popup?type=key&id="+id+"&c_a_r=1&section_id="+section_id+"&sign=1", false);
    xmlHttp.send();
    xmlHttp = null;

    String.prototype.replaceAll = function(s1,s2){     
        return this.replace(new RegExp(s1,'g'),s2);
    }

    text = text.split('参考答案</div>')[1];
    switch(type){
        case "判断题": //看作多选题
        case "单选题": //跟多选一起考虑
        case "多选题":
            dxtFunc(text);
            break;
        case "代码分析":
        case "代码填空":
            dmtkFunc(text);
            break;
        case "改错题":
        case "编程题":
            bctFunc(text);
            break;
        default:
            dropErr("答案已获取,但题型未知!题型:"+type);
            return false;
    }
    text = null;
    if(document.getElementById("exerSubBtn")){
        document.getElementById("exerSubBtn").click();
    }else{
        dropErr("答案已填充,但未找到提交按钮!");
        return false;
    }

    return true;
}

function dxtFunc(text){
    var answers = text.split('.<br />');
    var inputs = document.getElementsByTagName("input");
    
    for(var i = 0; i < answers.length-1; i++){
        if(answers[i].indexOf("、正确") != -1)
            inputs[i+1].checked = true;
        else if(answers[i].indexOf("、错误") != -1)
            inputs[i+1].checked = false;
        else
            dropErr("解析选择题答案时发生意外!");
    }

    answers = null;
    inputs = null;
}

function dmtkFunc(text){
    var answer = text.split('</div>')[0];
    answer = answer.substr(answer.indexOf('>')+4);
    answer = answer.substr(0,answer.length-2);
    
    answer = answer.replaceAll("<br />","");
    Coder.set(answer);

    answer = null;
}

function bctFunc(text){
    var answer = text.split("\n")[8];
    answer = answer.split(",'content':\"")[1].split("\",'courseLang':")[0];
    /*answer = answer.replaceAll("\\\\\\\\n","?换行");
    answer = answer.replaceAll("\\\\t","\t");
    answer = answer.replaceAll("\\\\r","\r");
    answer = answer.replaceAll("\\\\n","\n");
    answer = answer.replaceAll("\\\\/","/");
    answer = answer.replaceAll("\\\\\"","\"");
    answer = answer.replaceAll("\\\\\\\\","\\"); //hack
    answer = answer.replaceAll("?换行","\\n");*/
    var jsn = "{\"content\" : \"" + answer + "\"}";
    answer = JSON.parse(jsn).content;
    
    answer = answer.replaceAll("  "," ");
    Coder.set(answer);

    jsn = null;
    answer = null;
}

function dropErr(errStr){
    notify("错误", errStr);
}

function notify(title, contents){
    Notification.requestPermission(function(status){
        // 仅当值为 "granted" 时显示通知
        new Notification(title, {body: contents});
    });
}
//notify("测试","测试");