您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
支持功能:自动切换章节、自动切换视频、自动提交随机选项以记录答案、根据记录答案自动完成考试
// ==UserScript== // @name QFZ网大自动学习机 // @namespace http://tampermonkey.net/ // @version 0.2 // @description 支持功能:自动切换章节、自动切换视频、自动提交随机选项以记录答案、根据记录答案自动完成考试 // @author yuyang // @match https://kc.zhixueyun.com/ // @icon https://www.google.com/s2/favicons?sz=64&domain=zhixueyun.com // @grant none // @license MIT // ==/UserScript== const modal = document.createElement("div") const modalCss = "overflow:hidden;z-index:999999;position:absolute;width:400px;height:250px;background-color:white;bottom:5%;right:5%;font-size: 18px;padding: 4px;color: black;border: 4px red solid;" modal.style.cssText = modalCss modal.innerHTML += "小助手日志<br/>" document.body.appendChild(modal) function modalMessage(message) { modal.innerHTML += message + "<br/>" modal.scrollTop = modal.scrollHeight } function logWithColor(text) { console.log(`%c${text}`, 'color: #fff; background: #f40; font-size: 15px;border-radius:0 6px 6px 0;padding:6px;'); modalMessage(text) } function waitForElementReady(parent, selector, checker) { return new Promise((resolve) => { setTimeout(resolve, 5000) }) } window.addEventListener("beforeunload", (event) => { // Cancel the event as stated by the standard. event.preventDefault(); // Chrome requires returnValue to be set. event.returnValue = ""; }); async function pageSubjectDetail() { // 课程详情 logWithColor("课程详情页面") await waitForElementReady() logWithColor(`记录当前学习课程链接 ${window.location.href}`) localStorage.setItem("subject-detail", window.location.href) logWithColor("获取章节完成进度:") let chapterNodes = [...document.querySelectorAll("[id^='D294studyBtn']")] // 名字和完成状态 const status = chapterNodes.map(node => ({ title: node.querySelector(".name-des").innerText, isComplete: node.querySelector(".operation").querySelector(".small").innerText.includes("重新学习"), node: node })) console.table(status) const inComplete = status.find(s => !s.isComplete) if (!inComplete) { logWithColor("所有课程已完成") return } logWithColor(`找到最近的未完成课程: 「${inComplete.title}」 正在跳转...`) inComplete.node.querySelector(".name-des").click() setTimeout(() => window.close(), 3000) } async function pageStudyCourse() { // 获得当前学习是 视频 还是 考试 // 获取侧边栏信息以当前需要处理的任务 logWithColor("学习任务页面") if (!document.querySelector("#D195container")) { logWithColor("等待标识容器D195加载") await waitForElementReady(document, "#D195container", () => true) logWithColor("标识容器D195加载完成 开始执行") } const fetchCurrentInfo = () => { const sideContainerId = "#D196course-side-catalog" const sideItemNodes = [...document.querySelector(sideContainerId).querySelectorAll(".chapter-list-box")] const sideItemInfo = sideItemNodes.map(node => ({ id: node.id, name: node.querySelector(`div[title]:not([title=""])`).innerText.replaceAll(/第.*: /g, ""), type: node.querySelector(".section-item").querySelector(".item").innerHTML, isComplete: (node.querySelector(".section-item").querySelector(".item").innerHTML.includes("视频") && node.querySelector(".section-item").querySelector("span").innerText.includes("重新学习")) || (node.querySelector(".section-item").querySelector(".item").innerHTML.includes("考试") && node.querySelector(".section-item").querySelector("span").innerText.includes("成绩100")) || (node.querySelector(".section-item").querySelector(".item").innerHTML.includes("文档") && node.querySelector(".section-item").querySelector("span").innerText.includes("重新学习")) })) logWithColor("当前的学习进度") console.table(sideItemInfo) const incItem = sideItemInfo.find(info => !info.isComplete) if (!incItem) { logWithColor("本章已学完") } else { logWithColor("当前学习任务:" + incItem.name) } return incItem } let currentStudyInfo while (true) { // 更新当前任务 const res = fetchCurrentInfo() if (!res) { logWithColor("结束") // 没有未完成的任务了 break } else { currentStudyInfo = res } // 处理学习任务 // 切换对应任务 document.getElementById(currentStudyInfo.id).click() const totalParentSelector = ".player-content" await new Promise(resolve => setTimeout(resolve, 5000)) if (currentStudyInfo.type === "视频") { const video = document.querySelector("video") video.play() // video.setAttribute("autoplay", "true") // video.setAttribute("muted", "true") video.muted = true if (!document.querySelector("#D195container")) { logWithColor("视频任务 等待视频加载") // await waitForElementReady(document.querySelector(totalParentSelector), "div.vjs-current-time-display", () => true) // await waitForElementReady(document.querySelector(totalParentSelector), "div.vjs-control-text", (el) => el.innerHTML.includes("播放")) await waitForElementReady(document.querySelector(totalParentSelector), "div", () => !!document.querySelector(totalParentSelector).querySelector(".videojs-referse-btn")) } logWithColor("视频任务 加载完成") // 重新播放按钮 const refersebtn = document.querySelector(totalParentSelector).querySelector(".vjs-paused") if (refersebtn) { logWithColor("视频任务 点击恢复播放") // document.querySelector(".vjs-play-control").click() video.play() // refersebtn.click() } logWithColor("视频任务 等待视频播放中") await waitForElementReady(document.querySelector(".catalog-control"), {childList: true}, 0) } if (currentStudyInfo.type === "考试") { if (!document.querySelector(".demand-table")) { logWithColor("考试任务 等待考试记录加载") await waitForElementReady(document.querySelector(".player-content"), "div.demand-table", (element) => { return element.querySelector(".repeat-exam"); }) } logWithColor("考试任务 加载完成 检查完成状态") const statusNode = document.querySelector(totalParentSelector).querySelector(".neer-status") if (!statusNode) { logWithColor("考试任务 没有考试记录 点进去开始考试") let joinBtn = document.querySelector(totalParentSelector).querySelector(".new-exam") if (joinBtn == null) { joinBtn = document.querySelector(totalParentSelector).querySelector(".repeat-exam") } joinBtn.firstElementChild.click() setTimeout(() => window.close(), 3000) } else { logWithColor(`考试答案 ${getAnswer(currentStudyInfo.name)}`) if (getAnswer(currentStudyInfo.name) == null) { logWithColor("考试任务 有记录 进入收集答案") document.querySelector(totalParentSelector).querySelector(".new-exam").click() setTimeout(() => window.close(), 3000) } else { logWithColor("考试任务 有答案 进入开始考试") document.querySelector(totalParentSelector).querySelector(".repeat-exam").firstElementChild.click() setTimeout(() => window.close(), 3000) } } return } if (currentStudyInfo.type === "文档") { logWithColor("文档任务 等待文档加载") await waitForElementReady() } } logWithColor(`跳转到上次打开的课程详情页面 = ${localStorage.getItem("subject-detail")}`) window.open(localStorage.getItem("subject-detail"), "_blank") setTimeout(() => window.close(), 3000) } async function scoreDetail() { logWithColor("考试结果页面") const textSelector = "div[data-current='exam/exam/question/types/answer/choise:content']" const optionSelect = "div[data-current='exam/exam/question/types/answer/choise:options']" if (!document.querySelector(".preview-content")) { logWithColor("等待答案加载中") await waitForElementReady(document, textSelector, (el) => !!document.querySelector(".show-answer").querySelector(".custom-color-4")) logWithColor("答案加载完成") } logWithColor("正在收集答案") const optionList = [] while (true) { // 获取选项信息 const text = document.querySelector(".preview-content").querySelector(".show-answer").querySelector(".custom-color-4") const op = text.innerHTML.split(":")[1].trim() optionList.push(op) logWithColor(`题目${optionList.length} 选项: ${op} 已记录`) const bottomBtn = document.querySelector(".preview-content").querySelector(".m-bottom").firstElementChild if (bottomBtn.innerHTML.includes("上一题")) { logWithColor("已获取全部题目答案") break } if (bottomBtn.innerHTML.includes("下一题")) { logWithColor("加载下个题目") bottomBtn.click() await waitForElementReady(document, textSelector, (el) => !!document.querySelector(".show-answer").querySelector(".custom-color-4")) } } const answerData = { examTitle: document.querySelector(".achievement-head").querySelector(".title").getAttribute("title"), optionList } saveAnswer(answerData) logWithColor(`跳转到上次打开的课程详情页面 = ${localStorage.getItem("subject-detail")}`) window.open(localStorage.getItem("subject-detail"), "_blank") setTimeout(() => window.close(), 3000) } const KEY_ANSWER = "QFZ.answer" function saveAnswer(answer) { let pre = localStorage.getItem(KEY_ANSWER) let arr = [] if (pre == null || pre === "") { pre = "[]" localStorage.setItem(KEY_ANSWER, pre) } else { arr = JSON.parse(pre) } answer.examTitle = answer.examTitle.trim() if (arr.find(a => a.examTitle === answer.examTitle)) return arr.push(answer) localStorage.setItem(KEY_ANSWER, JSON.stringify(arr)) } function getAnswer(title) { let pre = localStorage.getItem(KEY_ANSWER) if (pre == null) { return null } const arr = JSON.parse(pre) const ol = arr.find(a => a.examTitle === title.trim()) if (ol != null) { return ol.optionList } else { return null } } async function pageExam() { logWithColor("考试页面") const textSelector = "div[data-current='exam/exam/question/types/answer/choise:content']" if (!document.querySelector(".preview-content")) { logWithColor("等待题目加载中") await waitForElementReady(document, textSelector, (el) => !!document.querySelector(".question").querySelector("span")) logWithColor("题目加载完成") } const examTitle = document.querySelector(".achievement-head").querySelector(".title").getAttribute("title") logWithColor(`当前考试标题: ${examTitle} 尝试获取答案`) const answer = getAnswer(examTitle) let opList; if (answer !== null) { logWithColor("找到答案 开始答题") opList = answer } else { logWithColor("未找到答案 随机回答并提交以获取正确答案") opList = ["A", "A"] } // 开始答题 while (true) { const op = opList.shift().split("") // 当前要作答的选项 // 所有选项列表 const ddList = document.querySelector("div[data-current='exam/exam/question/types/answer/choise:options']").querySelectorAll("dd") logWithColor("进行选择: " + op) ddList.forEach(d => { const leftNum = d.querySelector(".option-num").innerHTML op.forEach(o => { if(leftNum.includes(o)) { console.log(d.id) document.getElementById(d.id).querySelector("input").click() } }) }) const bottomBtn = document.querySelector(".preview-content").querySelectorAll(".m-bottom").item(1).firstElementChild console.log(bottomBtn) if (bottomBtn.innerHTML.includes("上一题")) { logWithColor("已作答全部题目 提交试卷") break } if (bottomBtn.innerHTML.includes("下一题")) { logWithColor("加载下个题目") bottomBtn.click() await waitForElementReady(document, textSelector, (el) => !!document.querySelector(".question").querySelector("span")) } } // 提交试卷 document.querySelector("#D165submit").click() await waitForElementReady(document, "#alertify", () => true) document.querySelector("#alertify").querySelector(".alertify-button-ok").click() logWithColor(`跳转到上次打开的课程详情页面 = ${localStorage.getItem("subject-detail")}`) window.open(localStorage.getItem("subject-detail"), "_blank") setTimeout(() => window.close(), 3000) } (async function() { 'use strict'; const href = window.location.href if (href.includes("study/subject/detail")) { await pageSubjectDetail() } if (href.includes("study/course/detail")) { await pageStudyCourse() } if (href.includes("exam/exam/front/score-detail")) { await scoreDetail() } if (href.includes("exam/exam/answer-paper")) { await pageExam() } })();