强国学习

问题反馈位置: https://github.com/TechXueXi/techxuexi-js/issues 。 强国学习自动答题,目前实现 每日答题,每周答题,专项答题(操作方法更新为:打开答题页面后,手动刷新下自动开启)

  1. // ==UserScript==
  2. // @name 强国学习
  3. // @namespace 雪导.
  4. // @version 2.1.1
  5. // @description 问题反馈位置: https://github.com/TechXueXi/techxuexi-js/issues 。 强国学习自动答题,目前实现 每日答题,每周答题,专项答题(操作方法更新为:打开答题页面后,手动刷新下自动开启)
  6. // @author 雪导、天幽
  7. // @require https://greasyfork.org/scripts/423313-utils%E7%8E%AF%E5%A2%83/code/Utils%E7%8E%AF%E5%A2%83.js?version=911306
  8. // @require http://cdn.bootcss.com/jquery/1.8.3/jquery.min.js
  9. // @match https://www.xuexi.cn
  10. // @match https://www.xuexi.cn/*
  11. // @match https://pc.xuexi.cn/points/exam-practice.html*
  12. // @match https://pc.xuexi.cn/points/exam-weekly-detail.html*
  13. // @match https://pc.xuexi.cn/points/exam-paper-detail.html*
  14. // @match https://pc.xuexi.cn/points/my-study.html*
  15. // @match https://pc.xuexi.cn/points/exam-index.html*
  16. // @match https://pc-api.xuexi.cn/open/api/score/today/queryrate
  17. // @grant none
  18. // ==/UserScript==
  19. window.onload = async function () {
  20. const $X = new Utils("学习强国");
  21. //移除顶部
  22. const header = document.querySelector("#app > div > div.layout-header");
  23. if (header != null) {
  24. header.parentNode.removeChild(header);
  25. console.log("移除header乱七八糟的dom");
  26. }
  27. //移除底部
  28. const footer = document.querySelector("#app > div > div.layout-footer");
  29. if (footer != null) {
  30. footer.parentNode.removeChild(footer);
  31. console.log("移除footer乱七八糟的dom");
  32. }
  33.  
  34. // 创建问题反馈
  35. const startQuestionBtn = () => {
  36. var div = document.createElement("div");
  37. div.innerHTML = "<span>问题反馈</span>";
  38. //为div创建属性class = "test"
  39. var divattr = document.createAttribute("class");
  40. divattr.value = "question-btn";
  41. //把属性class = "test"添加到div
  42. div.setAttributeNode(divattr);
  43. //为div添加样式
  44. var style = document.createAttribute("style");
  45. div.setAttributeNode(style);
  46. div.style.backgroundColor = "green";
  47. div.style.color = "#fff";
  48. div.style.textAlign = "center";
  49. div.style.width = "80px";
  50. div.style.borderColor = "#000";
  51. div.style.marginLeft = "0%";
  52. div.style.marginTop = "1%";
  53. document.querySelector(".ant-breadcrumb").appendChild(div);
  54. $(".question-btn").click(() => {
  55. window.open("https://gitee.com/qq34347476/tampermonkey/issues");
  56. });
  57. };
  58.  
  59. // 创建每日答题
  60. const startDayBtn = () => {
  61. var div = document.createElement("div");
  62. div.innerHTML = "<span>每日答题</span>";
  63. //为div创建属性class = "test"
  64. var divattr = document.createAttribute("class");
  65. divattr.value = "start-btn";
  66. //把属性class = "test"添加到div
  67. div.setAttributeNode(divattr);
  68. //为div添加样式
  69. var style = document.createAttribute("style");
  70. div.setAttributeNode(style);
  71. div.style.backgroundColor = "#F00";
  72. div.style.color = "#fff";
  73. div.style.textAlign = "center";
  74. div.style.width = "80px";
  75. div.style.borderColor = "#000";
  76. div.style.marginLeft = "0%";
  77. div.style.marginTop = "1%";
  78. document.querySelector(".ant-breadcrumb").appendChild(div);
  79. $(".start-btn").click(() => {
  80. window.open("https://pc.xuexi.cn/points/exam-practice.html");
  81. });
  82. };
  83.  
  84. // 创建专项答题
  85. const startExamBtn = () => {
  86. var div = document.createElement("div");
  87. div.innerHTML = "<span>专项答题</span>";
  88. //为div创建属性class = "test"
  89. var divattr = document.createAttribute("class");
  90. divattr.value = "start-btn3";
  91. //把属性class = "test"添加到div
  92. div.setAttributeNode(divattr);
  93. //为div添加样式
  94. var style = document.createAttribute("style");
  95. div.setAttributeNode(style);
  96. div.style.backgroundColor = "#F00";
  97. div.style.color = "#fff";
  98. div.style.textAlign = "center";
  99. div.style.width = "80px";
  100. div.style.borderColor = "#000";
  101. div.style.marginLeft = "0%";
  102. div.style.marginTop = "1%";
  103. document.querySelector(".ant-breadcrumb").appendChild(div);
  104. $(".start-btn3").click(() => {
  105. window.open("https://pc.xuexi.cn/points/exam-paper-list.html");
  106. });
  107. };
  108.  
  109. // 创建每周答题
  110. const startWeekBtn = () => {
  111. var div = document.createElement("div");
  112. div.innerHTML = "<span>每周答题</span>";
  113. //为div创建属性class = "test"
  114. var divattr = document.createAttribute("class");
  115. divattr.value = "start-btn2";
  116. //把属性class = "test"添加到div
  117. div.setAttributeNode(divattr);
  118. //为div添加样式
  119. var style = document.createAttribute("style");
  120. div.setAttributeNode(style);
  121. div.style.backgroundColor = "#F00";
  122. div.style.color = "#fff";
  123. div.style.textAlign = "center";
  124. div.style.width = "80px";
  125. div.style.borderColor = "#000";
  126. div.style.marginLeft = "0%";
  127. div.style.marginTop = "1%";
  128. document.querySelector(".ant-breadcrumb").appendChild(div);
  129. $(".start-btn2").click(() => {
  130. window.open("https://pc.xuexi.cn/points/exam-weekly-list.html");
  131. });
  132. };
  133.  
  134. const getBtnDom = async () => {
  135. return new Promise((resolve) => {
  136. setTimeout(() => {
  137. let nextAll = document.querySelectorAll(".ant-btn");
  138. let next = nextAll[0];
  139.  
  140. if (nextAll.length == 2) {
  141. //俩按钮,说明有个按钮是交卷。
  142. next = nextAll[1];
  143. }
  144. console.log("btn按钮状态", next);
  145. resolve(next);
  146. }, 2000);
  147. });
  148. };
  149.  
  150. const doit = async () => {
  151. console.log("===========开始答题===========");
  152. console.log("延时500ms");
  153. await $X.wait(500);
  154. const next = await getBtnDom();
  155. console.log("next", next);
  156.  
  157. if (next.disabled) {
  158. document.querySelector(".tips").click();
  159. console.log("延时500ms");
  160. await $X.wait(500);
  161. if (
  162. document.querySelector(".ant-popover-inner-content").textContent ===
  163. "请观看视频"
  164. ) {
  165. console.log("需要观看视频");
  166. alert("请手动作答");
  167. // window.location.reload()
  168. return;
  169. }
  170.  
  171. //所有提示
  172. let allTips = document.querySelectorAll("font[color=red]");
  173.  
  174. //单选多选时候的按钮
  175. let buttons = document.querySelectorAll(".q-answer");
  176.  
  177. //填空时候的那个textbox,这里假设只有一个填空
  178. let textboxs = document.querySelectorAll("input");
  179. //问题类型
  180. let qType = document.querySelector(".q-header").textContent;
  181. console.log("问题类型qType", qType);
  182.  
  183. qType = qType.substr(0, 3);
  184. switch (qType) {
  185. case "填空题":
  186. //第几个填空
  187. let mevent = new Event("input", { bubbles: true });
  188. if (textboxs.length > 1) {
  189. //若不止是一个空
  190. //填空数量和提示数量是否一致
  191. if (allTips.length == textboxs.length) {
  192. for (
  193. let i = 0;
  194. i < allTips.length;
  195. i++ //数量一致,则一一对应。
  196. ) {
  197. let tip = allTips[i];
  198. let tipText = tip.textContent;
  199. if (tipText.length > 0) {
  200. //通过设置属性,然后立即让他冒泡这个input事件.
  201. //否则1,setattr后,内容消失.
  202. //否则2,element.value=124后,属性值value不会改变,所以冒泡也不管用.
  203. textboxs[i].setAttribute("value", tipText);
  204. textboxs[i].dispatchEvent(mevent);
  205. }
  206. }
  207. } else {
  208. //若填空数量和提示数量不一致,那么,应该都是提示数量多。
  209.  
  210. if (allTips.length > textboxs.length) {
  211. let lineFeed = document.querySelector(".line-feed").textContent; //这个是提示的所有内容,不仅包含红色答案部分。
  212.  
  213. let n = 0; //计数,第几个tip。
  214. for (
  215. let j = 0;
  216. j < textboxs.length;
  217. j++ //多个填空
  218. ) {
  219. let tipText = allTips[n].textContent;
  220. let nextTipText = "";
  221. do {
  222. tipText += nextTipText;
  223. if (n < textboxs.length - 1) {
  224. n++;
  225. nextTipText = allTips[n].textContent;
  226. } else {
  227. nextTipText = "结束了,没有了。";
  228. }
  229. } while (lineFeed.indexOf(tipText + nextTipText));
  230.  
  231. textboxs[j].setAttribute("value", tipText);
  232. textboxs[j].dispatchEvent(mevent);
  233. }
  234. } else {
  235. //提示数量少于填空数量,则我无法分析, 回头研究,暂时放弃作答,刷新题库浏览器
  236. // location.reload()
  237. }
  238. return doit();
  239. }
  240. } else if (textboxs.length == 1) {
  241. //只有一个空,直接把所有tips合并。
  242. let tipText = "";
  243. for (let i = 0; i < allTips.length; i++) {
  244. tipText += allTips[i].textContent;
  245. }
  246. textboxs[0].setAttribute("value", tipText);
  247. textboxs[0].dispatchEvent(mevent);
  248. await $X.wait(500);
  249. // return doit()
  250. } else {
  251. //怕有没空白的情况。 看视频。。
  252. console.log("填空题,看视频?");
  253. window.location.href = "http://www.baidu.com";
  254. }
  255. return doit();
  256. case "多选题":
  257. //循环选项列表。用来点击
  258. for (let js = 0; js < buttons.length; js++) {
  259. let cButton = buttons[js];
  260. for (
  261. let i = 0;
  262. i < allTips.length;
  263. i++ //循环提示列表。
  264. ) {
  265. let tip = allTips[i];
  266. let tipText = tip.textContent;
  267. if (tipText.length > 0) {
  268. //提示内容长度大于0
  269. let cButtonText = cButton.textContent; //选项按钮的内容
  270. console.log("cButtonText", cButtonText);
  271. console.log("tipText", tipText);
  272. //循环对比点击
  273. if (
  274. cButtonText.indexOf(tipText) > -1 ||
  275. tipText.indexOf(cButtonText) > -1
  276. ) {
  277. cButton.click();
  278. }
  279. }
  280. }
  281. }
  282. return doit();
  283. case "单选题":
  284. //单选,所以所有的提示,其实是同一个。有时候,对方提示会分成多个部分。
  285. //case 块里不能直接用let。所以增加了个if。
  286. if (true) {
  287. //把红色提示组合为一条
  288. let tipText = "";
  289. for (let i = 0; i < allTips.length; i++) {
  290. tipText += allTips[i].textContent;
  291. }
  292.  
  293. if (tipText.length > 0) {
  294. //循环对比后点击 答案是否包含正确答案
  295. for (let js = 0; js < buttons.length; js++) {
  296. let cButton = buttons[js];
  297. let cButtonText = cButton.textContent;
  298. //通过判断是否相互包含,来确认是不是此选项
  299. if (
  300. cButtonText.indexOf(tipText) > -1 ||
  301. tipText.indexOf(cButtonText) > -1
  302. ) {
  303. console.log("延时500选择");
  304. await $X.wait(500);
  305. cButton.click();
  306. await $X.wait(500);
  307. console.log("下一步");
  308. return doit();
  309. }
  310. }
  311.  
  312. // 循环对比答案,若不纯在包含答案 则走 这套比对答案逻辑
  313. console.log("循环比对答案 【相似度】");
  314. let xiangsidu = []; // 相似度
  315. let max_xiangsidu = 0;
  316. let index = 0;
  317. for (let js = 0; js < buttons.length; js++) {
  318. let cButton = buttons[js];
  319. let cButtonText = cButton.textContent;
  320. //通过判断是否相互包含,来确认是不是此选项
  321. xiangsidu.push($X.strSimilarity2Percent(tipText, cButtonText));
  322. }
  323.  
  324. max_xiangsidu = $X.getMaxNumOfArr(xiangsidu);
  325. index = xiangsidu.findIndex((item) => item === max_xiangsidu);
  326. console.log(`几个答案相似度【$X{max_xiangsidu}】`);
  327. console.log(`找最相似的答案【$X{index}】`);
  328. buttons[index].click();
  329. await $X.wait(500);
  330. document.querySelector(".ant-btn").click();
  331. await $X.wait(500);
  332. return doit();
  333. }
  334. }
  335. break;
  336. default:
  337. break;
  338. }
  339. } else {
  340. // 可以点击
  341. if (
  342. next.textContent != "再练一次" &&
  343. next.textContent != "再来一组" &&
  344. next.textContent != "查看解析"
  345. ) {
  346. next.click();
  347. await $X.wait(500);
  348. doit();
  349. } else {
  350. // 结束
  351. console.log("答题结束");
  352. $X.done();
  353. }
  354. }
  355. };
  356. startQuestionBtn();
  357. startDayBtn();
  358. startWeekBtn();
  359. startExamBtn();
  360. let btn = document.querySelector(".ant-btn");
  361. if (btn) {
  362. if (btn.textContent === "确 定" || btn.textContent === "下一题") {
  363. await $X.wait(500);
  364. doit();
  365. } else {
  366. location.reload();
  367. }
  368. }
  369. };