Tominysun

前言

由于我的一门水课老师使用了雨课堂的MOOC进行授课,而这部分的成绩最终也按比例算在期末分数中。
于是我和好朋友合作完成,但在互通有无的过程中遇到了一点点小问题,答案交流实在太过繁琐
这怎能忍!我花了一点时间,完成了下述脚本,以加快知识共享的速度。

介绍

  1. 雨课堂单元测试导出
  2. 雨课堂考试结果(试卷)导出

单元测试

/*
 *Title: 雨课堂单元测试导出
 *Description: F12(/homework)
 *Author: Tominysun
 *Created: 2023/03/05
 *Updated: 2023/03/15
*/
var text = document.querySelector('.text.text-ellipsis').innerText + "\n";
for (var i = 1; i <= parseInt(document.querySelector('.aside-body--progress span').innerText); i++) {
    (function(t, data) { // 注意这里是形参
        setTimeout(function() {
            text += document.querySelector('.subject-item.active').innerText + "."; //题号;
            text += document.querySelector('.item-body').innerText + "\n"; //document.querySelector('.problem-body').innerHTML + "\n"; //题干
            text += document.querySelector('.problem-remark').innerText + "\n"; //.match(/正确答案:\s*(.*)/)[1] + "\n"; //正确答案
            document.querySelector('.text-right button').click(); //下一题
            //最后一题,输出txt
            if (parseInt(document.querySelector('.subject-item.active').innerText) === parseInt(document.querySelector('.aside-body--progress span').innerText)) {
                exportTxt(document.querySelector('.text.text-ellipsis').innerText + ".txt", text);
            }
        }, 1000 * t);
    })();
}

function exportTxt(fileName, data) {
    data = data.replace(/\n/g, "\r\n");
    if (navigator.userAgent.indexOf("Trident") >= 0) {
        try {
            // IE 10 或以上
            var fileObj = new Blob([data]);
            navigator.msSaveBlob(fileObj, fileName);
        } catch (ex) {
            // IE 9 或以下
            var winSave = window.open();
            winSave.document.open("text", "utf-8");
            winSave.document.write(data);
            winSave.document.execCommand("SaveAs", true, fileName);
            winSave.close();
        }
    } else {
        // Webkit
        var urlObject = window.URL || window.webkitURL || window;
        var export_blob = new Blob([data]);
        var save_link = document.createElement("a");
        save_link.href = urlObject.createObjectURL(export_blob);
        save_link.download = fileName;
        save_link.click();
    }
}

考试结果

/*
 *Title: 雨课堂考试结果(试卷)导出
 *Description: F12(https://examination.xuetangx.com/result/*)
 *Author: Tominysun
 *Created: 2023/03/15
 *Updated: 2023/03/15
*/
var text = document.querySelector(".header-title").innerText + "\n" + document.querySelector(".exam-main--body").innerText;
function exportTxt(fileName, data) {
    data = data.replace(/\n/g, "\r\n");
    if (navigator.userAgent.indexOf("Trident") >= 0) {
        try {
            // IE 10 或以上
            var fileObj = new Blob([data]);
            navigator.msSaveBlob(fileObj, fileName);
        } catch (ex) {
            // IE 9 或以下
            var winSave = window.open();
            winSave.document.open("text", "utf-8");
            winSave.document.write(data);
            winSave.document.execCommand("SaveAs", true, fileName);
            winSave.close();
        }
    } else {
        // Webkit
        var urlObject = window.URL || window.webkitURL || window;
        var export_blob = new Blob([data]);
        var save_link = document.createElement("a");
        save_link.href = urlObject.createObjectURL(export_blob);
        save_link.download = fileName;
        save_link.click();
    }
}
exportTxt(document.querySelector(".header-title").innerText + ".txt",text);

修改

以下是我最早的版本:

var text = $('.text.text-ellipsis').innerText + "\n";
document.addEventListener("keydown",keydown);
function keydown(event) {
    if (event.keyCode == 83) { //event.ctrlKey && event.altKey &&
        for (var i = 1; i <= parseInt($('.aside-body--progress span').innerText); i++) {
            (function(t, data) { // 注意这里是形参
                setTimeout(function() {
                    text += $('.subject-item.active').innerText + "."; //题号;
                    text += $('.item-body').innerText + "\n"; //$('.problem-body').innerHTML + "\n"; //题干
                    text += $('.problem-remark').innerText + "\n"; //.match(/正确答案:\s*(.*)/)[1] + "\n"; //正确答案
                    $('.text-right button').click(); //下一题
                    //if(t = parseInt($('.aside-body--progress span').innerText)){alert(text);}
                }, 1000 * t);
            })();
        }
    }
    if (event.keyCode == 67) { //event.ctrlKey && event.altKey &&
        alert(text);
    }
}
alert('用户脚本开始执行!按s键开始,结束后按c键复制。');

为方便执行,压缩后代码如下。

eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('5 0=$(\'.0.0-e\').2+"\\n";f.g("3",3);4 3(b){6(b.7==h){j(5 i=1;i<=k($(\'.l-8--m o\').2);i++){(4(t,a){p(4(){0+=$(\'.q-9.r\').2+".";0+=$(\'.9-8\').2+"\\n";0+=$(\'.u-v\').2+"\\n";$(\'.0-w x\').y()},z*t)})()}}6(b.7==A){d(0)}}d(\'用户脚本开始执行!按s键开始,结束后按c键复制。\');',37,37,'text||innerText|keydown|function|var|if|keyCode|body|item||||alert|ellipsis|document|addEventListener|83||for|parseInt|aside|progress||span|setTimeout|subject|active|||problem|remark|right|button|click|1000|67'.split('|'),0,{}))
我当时的开发及调试环境是Firefox,但上述脚本迁移到Chrome(Edge)平台后无法运行
我目前对具体错误原因尚不得而知,但修Bug的思路还是很明确的。将所有使用Jquery的部分全部改为原生JS实现,即可完美修复原有的Bug。

以下是修复后的版本:

var text = document.querySelector('.text.text-ellipsis').innerText + "\n";
document.addEventListener("keydown",keydown);
function keydown(event) {
    if (event.keyCode == 83) { //event.ctrlKey && event.altKey &&
        for (var i = 1; i <= parseInt(document.querySelector('.aside-body--progress span').innerText); i++) {
            (function(t, data) { // 注意这里是形参
                setTimeout(function() {
                    text += document.querySelector('.subject-item.active').innerText + "."; //题号;
                    text += document.querySelector('.item-body').innerText + "\n"; //document.querySelector('.problem-body').innerHTML + "\n"; //题干
                    text += document.querySelector('.problem-remark').innerText + "\n"; //.match(/正确答案:\s*(.*)/)[1] + "\n"; //正确答案
                    document.querySelector('.text-right button').click(); //下一题
                    //if(t = parseInt(document.querySelector('.aside-body--progress span').innerText)){alert(text);}
                }, 1000 * t);
            })();
        }
    }
    if (event.keyCode == 67) { //event.ctrlKey && event.altKey &&
        //alert(text);
        copy();
    }
    if (event.keyCode == 68) {
        exportTxt(document.querySelector('.text.text-ellipsis').innerText + ".txt",text);
    }
}
function copy() {
    const txt = text;
    // 添加一个input元素放置需要的文本内容
    const dataContainer = document.createElement('textarea');
    dataContainer.value = txt;
    document.body.appendChild(dataContainer);
    // 选中并复制文本到剪切板
    dataContainer.select();
    document.execCommand('copy');
    // 移除input元素
    document.body.removeChild(dataContainer);
    alert('复制成功');
}
function exportTxt(fileName, data) {
    data = data.replace(/\n/g, "\r\n");
    if (navigator.userAgent.indexOf("Trident") >= 0) {
        try {
            // IE 10 或以上
            var fileObj = new Blob([data]);
            navigator.msSaveBlob(fileObj, fileName);
        } catch (ex) {
            // IE 9 或以下
            var winSave = window.open();
            winSave.document.open("text", "utf-8");
            winSave.document.write(data);
            winSave.document.execCommand("SaveAs", true, fileName);
            winSave.close();
        }
    } else {
        // Webkit
        var urlObject = window.URL || window.webkitURL || window;
        var export_blob = new Blob([data]);
        var save_link = document.createElement("a");
        save_link.href = urlObject.createObjectURL(export_blob);
        save_link.download = fileName;
        save_link.click();
    }
}
alert('用户脚本开始执行!按s键开始,结束后按c键复制,按d键下载。');

为方便执行,压缩后代码如下。

eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('4 3=2.5(\'.3.3-q\').6+"\\n";2.F("l",l);7 l(b){h(b.m==G){H(4 i=1;i<=I(2.5(\'.J-j--K L\').6);i++){(7(t,a){M(7(){3+=2.5(\'.N-u.O\').6+".";3+=2.5(\'.u-j\').6+"\\n";3+=2.5(\'.P-Q\').6+"\\n";2.5(\'.3-R S\').v()},T*t)})()}}h(b.m==U){o()}h(b.m==V){w(2.5(\'.3.3-q\').6+".p",3)}}7 o(){x p=3;x 9=2.y(\'W\');9.X=p;2.j.Y(9);9.Z();2.z(\'o\');2.j.10(9);A(\'复制成功\')}7 w(a,b){b=b.11(/\\n/g,"\\r\\n");h(B.12.13("14")>=0){15{4 c=C D([b]);B.16(c,a)}17(18){4 d=k.E();d.2.E("3","19-8");d.2.1a(b);d.2.z("1b",1c,a);d.1d()}}1e{4 e=k.1f||k.1g||k;4 f=C D([b]);4 g=2.y("a");g.1h=e.1i(f);g.1j=a;g.v()}}A(\'用户脚本开始执行!按s键开始,结束后按c键复制,按d键下载。\');',62,82,'||document|text|var|querySelector|innerText|function||dataContainer||||||||if||body|window|keydown|keyCode||copy|txt|ellipsis||||item|click|exportTxt|const|createElement|execCommand|alert|navigator|new|Blob|open|addEventListener|83|for|parseInt|aside|progress|span|setTimeout|subject|active|problem|remark|right|button|1000|67|68|textarea|value|appendChild|select|removeChild|replace|userAgent|indexOf|Trident|try|msSaveBlob|catch|ex|utf|write|SaveAs|true|close|else|URL|webkitURL|href|createObjectURL|download'.split('|'),0,{}))

上述代码的实现方式依赖手动操作,最终版本实现完全自动化,取消复制,并且使用txt导出。

学习

在上述编写过程中,绝大部分内容都是互联网随处可找。整体脚本技术含量可以忽略。
但还是学到了一点(或者说发现了原来忽视的东西)。

data = data.replace(/\n/g, "\r\n");

注意到上述这行代码了吗?
最开始的txt导出函数,会导致原来字符串中的换行无法正确显示。
我一开始愣是找不到哪里出了问题。
因为我使用\n在浏览器环境并没有出现问题,但导出生成txt后就无法正确显示。
原因在于Windows系统环境下,换行符需要使用\r\n
因此,生成txt之前,使用正则进行一次批量替换,即可解决。

(上述bug的解决方案是New Bing告诉我的...)

鸣谢

  • New Bing

添加新评论