// ==UserScript== // @name 超星 To Csv // @version 0.2.0 // @description 将你的超星学习通里的作业数据、随堂练习导出成为 Csv 文件,方便导入 Anki 背题 // @author Nexmoe // @github https://github.com/nexmoe/chaoxing2csv // @namespace https://nexmoe.com/ // @match *://*.chaoxing.com/* // @license MIT // ==/UserScript== const getPage = () => { if (document.querySelector(".detailsHead")) { return "homework"; } else if (document.querySelector(".top-box")) { return "practice"; } else if (document.querySelector(".CeYan")) { return "ceyan"; } else { return "invalid"; } } const page = getPage(); const chaoxing2csv = { typeList: [ "(单选题)", "(多选题)", "(判断题)", ], typeToKey: { "(单选题)": "select", "(多选题)": "select", "(判断题)": "select", }, homework: { type: ".mark_name .colorShallow", title: ".mark_title", textarea: ".detailsHead", list: ".questionLi", select: { question: ".mark_name", options: ".mark_letter", options2: ".stem_answer", answer: ".colorGreen", answer2: ".check_answer" }, }, practice: { type: ".topic-title .topic-type", title: ".textHeightauto", textarea: ".top-box", list: ".question-list", select: { question: ".topic-title", options: ".topic-options", answer: ".color-green" }, }, ceyan: { title: ".ZyTop h3", textarea: ".ZyTop", list: ".TiMu", } } const generateTextArea = (data) => { let node = document.createElement("textarea"); node.style = ` width: 100%; resize: none; padding: 12px; background-color: #171717; color: #fff; box-sizing: border-box; height: 70px;`; let textnode = document.createTextNode(data); node.appendChild(textnode); document.querySelector(chaoxing2csv[page].textarea).appendChild(node); } function ConvertToCSV(objArray) { var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray; var str = ''; for (var i = 0; i < array.length; i++) { var line = ''; for (var index in array[i]) { if (line != '') line += ',' line += array[i][index]; } str += line + '\r\n'; } return str; } let saveFile = (data) => { const blob = new Blob([data], { type: 'text/csv;charset=utf-8;' }); const Url = URL.createObjectURL(blob); let link = document.createElement('a'); link.href = Url; link.appendChild(document.createTextNode('下载题目 CSV 数据')); link.download = document.querySelector(chaoxing2csv[page].title).innerHTML + '.csv'; //文件名字 document.querySelector(chaoxing2csv[page].textarea).appendChild(link); } let optionsFilter = (dom, i = 0, strings = "") => { for (i = 0; i < dom.children.length; i++) { if (i < (dom.children.length - 1)) { strings = strings + dom.children[i].innerText + "||"; } else { strings = strings + dom.children[i].innerText; } } return strings.replace( new RegExp(",", "gm"), "," ).replace( new RegExp("\n", "gm"), "" ); } let answersFilter = (dom, i = 0, strings = "") => { try { answer = dom.innerText.replace("正确答案: ", "").replace( new RegExp(",", "gm"), "," ).replace( new RegExp(" ", "gm"), "" ).replace( new RegExp("对", "gm"), "A" ).replace( new RegExp("错", "gm"), "B" ); for (i = 0; i < answer.length; i++) { if (i < (answer.length - 1)) { strings = strings + (answer.charCodeAt(i) - 64) + "||" } else { strings = strings + (answer.charCodeAt(i) - 64) } } } catch (e) { strings = dom.innerHTML; console.error(e) } return strings; } let questionsFilter = (dom, answers, i = 0, strings = "") => { let question; try { question = dom.innerHTML.replace( new RegExp(",", "gm"), "," ).replace( new RegExp("\n", "gm"), "" ).replace( new RegExp("http://", "gm"), "https://" ); answer = answers.innerText.replace("正确答案: ", "").replace( new RegExp(",", "gm"), "," ).replace( new RegExp(" ", "gm"), "" ).replace( new RegExp("对", "gm"), "A" ).replace( new RegExp("错", "gm"), "B" ); for (i = 0; i < answer.split('\n').length; i++) { strings = strings + "{{c" + (i + 1) + "::}}" } } catch (e) { console.error(e) } return question + strings; } let getData = (i, data = []) => { let questionList = document.querySelectorAll(chaoxing2csv[page].list); for (let child of questionList) { let type, question, options, answer, questItem; type = child.querySelector(chaoxing2csv[page].type).innerText.replace(" ", ""); if (!chaoxing2csv.typeList.includes(type)) { console.log("不支持:", type) continue; } else { type = chaoxing2csv.typeToKey[type]; } const qDom = child.querySelector(chaoxing2csv[page][type].question); const oDom = child.querySelector(chaoxing2csv[page][type].options) || child.querySelector(chaoxing2csv[page][type].options2); const aDom = child.querySelector(chaoxing2csv[page][type].answer) || child.querySelector(chaoxing2csv[page][type].answer2); try { question = questionsFilter(qDom, aDom); } catch (e) { console.error(e) } try { options = optionsFilter(oDom); } catch (e) { console.error(e) } try { answer = answersFilter(aDom); } catch (e) { console.error(e) } questItem = { question, options, answer, id: String(new Date().getTime()) + String(Math.floor(Math.random() * 100000)), type, } console.log(questItem) data.push(questItem) } return data; } (() => { for (let child of document.querySelectorAll(".questionLi *")) { child.style = ""; delete child.style; } setTimeout(() => { console.log(page) if (page !== "invalid") { const data = JSON.stringify(getData()); generateTextArea(ConvertToCSV(data)); saveFile(ConvertToCSV(data)); } }, 1000) })();