// ==UserScript== // @name 东奥+正保会计继续教育专属全自动助手(精细校准版) // @namespace http://tampermonkey.net/ // @version 3.5.0 // @description 东奥会计在线+正保会计网校专属适配,三级课程遍历、深度反作弊、自动考试、验证码识别、可拖拽面板 // @author 技术研究用途 // @match *://*.dongao.cn/* // @match *://*.chinaacc.com/* // @grant none // @run-at document-end // @license MIT // ==/UserScript== (function () { 'use strict'; // ===================== 平台专属配置库(精细校准) ===================== const PLATFORM_CONFIGS = { // ========== 东奥会计在线 专属精细配置 ========== dongao: { name: "东奥会计在线", match: /dongao\.cn/, selectors: { // 课程列表页 courseItem: '.course-item, .kc-item', unfinishedCourse: '.course-item.status-unfinish, .kc-item.no-study', courseTitle: '.course-name, .kc-title', courseEnterBtn: '.study-btn, .enter-study, .btn-study', // 课程内章节列表 chapterItem: '.chapter-item, .section-item', unfinishedChapter: '.chapter-item.unfinish, .section-item.no-study', chapterTitle: '.chapter-name, .section-title', chapterPlayBtn: '.play-btn, .btn-play', nextChapterBtn: '.next-section-btn, .btn-next', // 视频播放器 videoPlayer: 'video', playerBox: '.player-box, .video-player', progressBar: '.progress-bar-inner', // 验证码(中途弹窗+考试前) captchaModal: '.verify-modal, .captcha-dialog', captchaImg: '#verifyImg, .captcha-img img', captchaInput: '#verifyCode, .captcha-input', captchaSubmit: '#btnSubmit, .captcha-confirm-btn', // 考试页面 questionItem: '.question-item, .exam-question', questionTitle: '.question-stem, .q-title', optionSingle: '.option-item input[type="radio"] + label, .option-single', optionMulti: '.option-item input[type="checkbox"] + label, .option-multi', judgeTrue: '.judge-option.true, .option-true', judgeFalse: '.judge-option.false, .option-false', fillInput: '.fill-blank input, .blank-input', submitPaperBtn: '#submitPaper, .btn-submit-paper', confirmSubmitBtn: '.dialog-confirm-btn, .el-button--primary', scoreText: '.score-number, .exam-score-value', retryBtn: '#reExam, .btn-retake-exam' }, special: { chapterMode: true, // 启用章节遍历模式 captchaInterval: 180, // 每180秒检查一次验证码弹窗 antiPause: true // 强制防视频暂停 } }, // ========== 正保会计网校(原中华)专属精细配置 ========== chinaacc: { name: "正保会计网校", match: /chinaacc\.com/, selectors: { // 课程列表页 courseItem: '.course-card, .kc_list li', unfinishedCourse: '.course-card.unfinish, .kc_list li.weiwancheng', courseTitle: '.course-title, .kc_name', courseEnterBtn: '.study-btn, .btn_xx, .enter-study', // 课程内章节 chapterItem: '.chapter-item, .zhangjie li', unfinishedChapter: '.chapter-item.unfinish, .zhangjie li.wc', chapterTitle: '.chapter-name, .zj_name', chapterPlayBtn: '.play-btn, .bf_btn', nextChapterBtn: '.next-chapter-btn, .xia_yi_zhang', // 视频播放器 videoPlayer: 'video', playerBox: '.player-wrap, .video-box', progressBar: '.progress-bar', // 验证码 captchaModal: '.code-dialog, .verify-box', captchaImg: '#codeImg, .code-img img', captchaInput: '#codeInput, .code-input', captchaSubmit: '#btnCode, .code-submit-btn', // 考试页面 questionItem: '.timu_item, .quest-item', questionTitle: '.tm_title, .quest-title', optionSingle: '.xx_dan li, .opt-single', optionMulti: '.xx_duo li, .opt-multi', judgeTrue: '.pd_zq, .judge-yes', judgeFalse: '.pd_cw, .judge-no', fillInput: '.tk_input, .fill-input', submitPaperBtn: '#tj_btn, .btn_tijiao', confirmSubmitBtn: '.confirm-btn, .queding_btn', scoreText: '.cj_num, .score-num', retryBtn: '#cxks, .btn_chongkao' }, special: { chapterMode: true, autoSyncStudy: true, // 自动同步学习时间 syncInterval: 120 // 每120秒触发一次学时同步 } } }; // 全局基础配置 const GLOBAL_CONFIG = { passScore: 60, maxRetry: 4, videoMuted: true, answerDelaySingle: [5000, 7000], // 单选/判断 5-7秒 answerDelayFill: [10000, 12000], // 填空 10-12秒 activityInterval: 25000, // 活跃度模拟间隔 questionBank: [ { question: "会计的基本职能包括核算和监督。", type: "judge", answer: "正确" }, { question: "下列各项中,属于会计要素的有", type: "multi", answer: "资产,负债,所有者权益" }, { question: "企业会计核算的基础是", type: "single", answer: "权责发生制" }, { question: "会计恒等式:资产 = 负债 + ________", type: "fill", answer: "所有者权益" } ] }; // 自动识别当前平台 let currentPlatform = null; let SELECTORS = {}; let SPECIAL = {}; for (const key in PLATFORM_CONFIGS) { const cfg = PLATFORM_CONFIGS[key]; if (cfg.match.test(window.location.hostname)) { currentPlatform = cfg; SELECTORS = cfg.selectors; SPECIAL = cfg.special || {}; break; } } // ------------------------------ 工具函数 ------------------------------ const Utils = { randomDelay(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }, similarity(str1, str2) { const s1 = str1.trim().replace(/[\s\W]/g, ''); const s2 = str2.trim().replace(/[\s\W]/g, ''); if (s1 === s2) return 1; const len = Math.max(s1.length, s2.length); if (len === 0) return 1; let match = 0; for (let i = 0; i < s1.length; i++) { if (s2.includes(s1[i])) match++; } return match / len; }, log(msg, type = 'info') { const time = new Date().toLocaleTimeString(); const text = `[${time}] [${type.toUpperCase()}] ${msg}`; console.log(text); UI.appendLog(text); }, waitFor(selector, timeout = 15000) { return new Promise((resolve, reject) => { const timer = setInterval(() => { const el = document.querySelector(selector); if (el && el.offsetParent !== null) { clearInterval(timer); resolve(el); } }, 500); setTimeout(() => { clearInterval(timer); reject(new Error(`元素超时未找到: ${selector}`)); }, timeout); }); }, async humanMoveTo(element) { if (!element) return; const rect = element.getBoundingClientRect(); const targetX = rect.left + rect.width / 2 + this.randomDelay(-12, 12); const targetY = rect.top + rect.height / 2 + this.randomDelay(-6, 6); const steps = this.randomDelay(10, 18); const startX = window.mouseX || window.innerWidth / 2; const startY = window.mouseY || window.innerHeight / 2; for (let i = 1; i <= steps; i++) { const x = startX + (targetX - startX) * (i / steps) + Math.sin(i / 2) * 3; const y = startY + (targetY - startY) * (i / steps) + Math.cos(i / 2) * 2; document.dispatchEvent(new MouseEvent('mousemove', { clientX: x, clientY: y, bubbles: true, cancelable: true })); window.mouseX = x; window.mouseY = y; await new Promise(r => setTimeout(r, 15)); } }, sleep(ms) { return new Promise(r => setTimeout(r, ms)); } }; // ------------------------------ 深度反作弊模块(双平台专属) ------------------------------ const AntiCheat = { init() { this.hijackVisibilityDeep(); this.startActivitySimulation(); this.hookVideoAntiPause(); // 平台专属反作弊 if (currentPlatform?.name === '东奥会计在线') { this.dongaoSpecial(); } if (currentPlatform?.name === '正保会计网校') { this.chinaaccSpecial(); } Utils.log(`深度反作弊模块已加载,当前平台:${currentPlatform?.name || '通用模式'}`); }, // 深度劫持可见性与失焦检测 hijackVisibilityDeep() { // 重写核心属性 Object.defineProperty(document, 'hidden', { value: false, writable: false, configurable: false }); Object.defineProperty(document, 'visibilityState', { value: 'visible', writable: false, configurable: false }); document.hasFocus = () => true; window.focus = () => true; // 捕获阶段拦截所有失焦/可见性事件 ['visibilitychange', 'blur', 'focusout', 'pagehide'].forEach(evt => { window.addEventListener(evt, e => e.stopImmediatePropagation(), true); document.addEventListener(evt, e => e.stopImmediatePropagation(), true); }); // 注入页面级覆盖脚本 const injectJS = ` (function(){ const _origDesc = Object.getOwnPropertyDescriptor(Document.prototype, 'hidden'); Object.defineProperty(document, 'hidden', { value: false, writable: false, configurable: false }); Object.defineProperty(document, 'visibilityState', { value: 'visible', writable: false, configurable: false }); document.hasFocus = function(){ return true; }; })(); `; const script = document.createElement('script'); script.textContent = injectJS; document.documentElement.appendChild(script); script.remove(); }, // 真人活跃度模拟 startActivitySimulation() { setInterval(() => { if (!window.autoRunning) return; // 随机滚动页面 window.scrollBy({ top: Utils.randomDelay(-60, 120), behavior: 'smooth' }); // 随机鼠标移动 const x = Utils.randomDelay(100, window.innerWidth - 100); const y = Utils.randomDelay(100, window.innerHeight - 100); document.dispatchEvent(new MouseEvent('mousemove', { clientX: x, clientY: y, bubbles: true })); window.mouseX = x; window.mouseY = y; // 30%概率点击空白区域 if (Math.random() > 0.7) { document.body.dispatchEvent(new MouseEvent('click', { clientX: x, clientY: y, bubbles: true })); } }, GLOBAL_CONFIG.activityInterval); }, // 视频防暂停钩子 hookVideoAntiPause() { const observer = new MutationObserver(() => { const videos = document.querySelectorAll('video'); videos.forEach(v => { // 强制静音 if (GLOBAL_CONFIG.videoMuted) { v.muted = true; v.volume = 0; } // 拦截暂停事件,自动恢复播放 v.addEventListener('pause', () => { if (window.autoRunning && SPECIAL.antiPause) { setTimeout(() => v.play().catch(() => {}), 500); } }); // 禁止快进检测:不修改currentTime,仅自然播放 }); }); observer.observe(document.body, { childList: true, subtree: true }); }, // 东奥专属反作弊优化 dongaoSpecial() { Utils.log('加载东奥专属反作弊策略:播放器区域模拟交互、防中断'); setInterval(() => { if (!window.autoRunning) return; const player = document.querySelector(SELECTORS.playerBox); if (player) { // 模拟鼠标在播放器内移动,防止挂机判定 const rect = player.getBoundingClientRect(); const x = rect.left + Utils.randomDelay(50, rect.width - 50); const y = rect.top + Utils.randomDelay(50, rect.height - 50); player.dispatchEvent(new MouseEvent('mousemove', { clientX: x, clientY: y, bubbles: true })); } }, 15000); }, // 正保专属反作弊优化 chinaaccSpecial() { Utils.log('加载正保专属策略:自动同步学时、拦截中断弹窗'); if (SPECIAL.autoSyncStudy) { setInterval(() => { if (!window.autoRunning) return; // 自动触发学时同步 const syncBtn = document.querySelector('.sync-btn, .tongbu_btn'); if (syncBtn) syncBtn.click(); // 自动关闭学习提示弹窗 document.querySelectorAll('.dialog-close, .close-btn').forEach(btn => { if (btn.offsetParent !== null) btn.click(); }); }, SPECIAL.syncInterval * 1000); } } }; // ------------------------------ 验证码识别模块 ------------------------------ const CaptchaSolver = { async init() { if (window.Tesseract) return; const script = document.createElement('script'); script.src = 'https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js'; document.head.appendChild(script); await new Promise(resolve => script.onload = resolve); Utils.log('OCR验证码识别引擎加载完成'); }, async solve(imgSelector) { try { const img = document.querySelector(imgSelector); if (!img) return null; await this.init(); const result = await Tesseract.recognize(img.src, 'eng', { tessedit_char_whitelist: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' }); const code = result.data.text.trim().replace(/\s/g, '').substring(0, 4); Utils.log(`验证码识别结果: ${code}`); return code; } catch (e) { Utils.log(`验证码识别失败: ${e.message}`, 'error'); return null; } }, // 检测并处理所有验证码弹窗 async checkAndSolve() { const modal = document.querySelector(SELECTORS.captchaModal); if (!modal || modal.offsetParent === null) return false; Utils.log('检测到验证码弹窗,正在识别...'); const code = await this.solve(SELECTORS.captchaImg); if (!code) return false; const input = document.querySelector(SELECTORS.captchaInput); const submit = document.querySelector(SELECTORS.captchaSubmit); if (!input || !submit) return false; await Utils.humanMoveTo(input); input.focus(); input.value = code; input.dispatchEvent(new Event('input', { bubbles: true })); input.dispatchEvent(new Event('change', { bubbles: true })); await Utils.sleep(800); await Utils.humanMoveTo(submit); submit.click(); Utils.log('验证码已提交'); await Utils.sleep(1500); return true; } }; // ------------------------------ 自动学习模块(三级遍历优化) ------------------------------ const CourseLearner = { async start() { Utils.log('=== 自动学习模块启动(课程→章节→小节 三级遍历) ==='); UI.updateStatus('学习中', '正在扫描未完成课程...'); // 1. 获取课程列表 const courses = document.querySelectorAll(SELECTORS.unfinishedCourse); if (courses.length === 0) { Utils.log('课程列表页未找到未完成课程,尝试检测章节页...'); // 如果已经在课程内,直接学习章节 if (document.querySelector(SELECTORS.chapterItem)) { await this.studyAllChapters(); return true; } Utils.log('未发现可学习内容,学习阶段结束'); return true; } Utils.log(`共找到 ${courses.length} 门未完成课程,将按顺序逐章学习`); // 2. 遍历每门课程 for (let i = 0; i < courses.length; i++) { if (!window.autoRunning) break; const course = courses[i]; const title = course.querySelector(SELECTORS.courseTitle)?.textContent.trim() || `第${i+1}门课程`; UI.updateStatus('课程学习中', title, courses.length - i); Utils.log(`===== 进入课程:${title} =====`); // 进入课程 const enterBtn = course.querySelector(SELECTORS.courseEnterBtn); await Utils.humanMoveTo(enterBtn); enterBtn.click(); await Utils.sleep(3500); // 学习该课程下所有章节 await this.studyAllChapters(); Utils.log(`课程《${title}》全部章节学习完成`); // 返回课程列表 history.back(); await Utils.sleep(2500); } Utils.log('=== 全部课程学习完成 ==='); UI.updateStatus('学习完成', '所有课程已结束'); return true; }, // 学习当前课程下所有章节 async studyAllChapters() { await Utils.sleep(2000); const chapters = document.querySelectorAll(SELECTORS.unfinishedChapter); if (chapters.length === 0) { Utils.log('当前课程无未完成章节'); return; } Utils.log(`当前课程共 ${chapters.length} 个未完成小节`); for (let j = 0; j < chapters.length; j++) { if (!window.autoRunning) break; const chapter = chapters[j]; const title = chapter.querySelector(SELECTORS.chapterTitle)?.textContent.trim() || `第${j+1}小节`; Utils.log(`开始学习小节:${title}`); // 点击播放 const playBtn = chapter.querySelector(SELECTORS.chapterPlayBtn) || chapter; await Utils.humanMoveTo(playBtn); playBtn.click(); await Utils.sleep(3000); // 监听播放进度 await this.watchVideoProgress(title); Utils.log(`小节完成:${title}`); } }, // 监听单个视频播放进度 async watchVideoProgress(title) { return new Promise(resolve => { const timer = setInterval(async () => { if (!window.autoRunning) { clearInterval(timer); resolve(); return; } // 定时检查验证码 await CaptchaSolver.checkAndSolve(); // 获取播放进度 const video = document.querySelector(SELECTORS.videoPlayer); if (video && video.duration && !isNaN(video.duration)) { const progress = video.currentTime / video.duration; if (progress >= 0.98) { clearInterval(timer); resolve(); } } }, 6000); }); } }; // ------------------------------ 自动考试模块(精细适配) ------------------------------ const ExamTaker = { async start() { Utils.log('=== 自动考试模块启动 ==='); let retryCount = 0; while (retryCount < GLOBAL_CONFIG.maxRetry && window.autoRunning) { UI.updateStatus('考试中', `第 ${retryCount + 1} 次考试`); Utils.log(`第 ${retryCount + 1} 次考试开始`); // 处理入场验证码 await CaptchaSolver.checkAndSolve(); await Utils.sleep(2000); // 获取所有题目 const questions = document.querySelectorAll(SELECTORS.questionItem); if (questions.length === 0) { Utils.log('未找到考试题目,页面可能未加载完成', 'error'); retryCount++; continue; } Utils.log(`本次考试共 ${questions.length} 道题`); // 逐题作答 for (let i = 0; i < questions.length; i++) { if (!window.autoRunning) break; await this.answerQuestion(questions[i], i + 1); } // 提交试卷 Utils.log('答题完成,准备提交试卷'); const submitBtn = document.querySelector(SELECTORS.submitPaperBtn); if (submitBtn) { await Utils.humanMoveTo(submitBtn); submitBtn.click(); await Utils.sleep(2000); // 确认提交弹窗 const confirmBtn = document.querySelector(SELECTORS.confirmSubmitBtn); if (confirmBtn) { await Utils.humanMoveTo(confirmBtn); confirmBtn.click(); } } // 等待成绩加载 await Utils.sleep(5000); const scoreEl = document.querySelector(SELECTORS.scoreText); if (!scoreEl) { Utils.log('无法获取考试成绩,流程异常', 'error'); retryCount++; continue; } const score = parseFloat(scoreEl.textContent.trim()); Utils.log(`本次考试得分:${score} 分`); if (score >= GLOBAL_CONFIG.passScore) { Utils.log('🎉 考试通过!'); UI.updateStatus('考试通过', `最终得分:${score}分`); return true; } else { retryCount++; if (retryCount >= GLOBAL_CONFIG.maxRetry) { Utils.log('已达最大重试次数,考试结束'); break; } Utils.log(`未及格,准备第 ${retryCount + 1} 次补考`); const retryBtn = document.querySelector(SELECTORS.retryBtn); if (retryBtn) { await Utils.humanMoveTo(retryBtn); retryBtn.click(); await Utils.sleep(3000); } else { Utils.log('未找到补考按钮,结束考试', 'error'); break; } } } UI.updateStatus('考试结束', '已达最大重试次数'); return false; }, async answerQuestion(questionEl, index) { const titleEl = questionEl.querySelector(SELECTORS.questionTitle); if (!titleEl) return; const title = titleEl.textContent.trim(); Utils.log(`作答第 ${index} 题:${title.substring(0, 35)}...`); // 题库模糊匹配 const match = this.matchBank(title); if (!match) { Utils.log(`第 ${index} 题未匹配到答案`, 'warn'); return; } switch (match.type) { case 'single': await this.answerSingle(questionEl, match.answer); await Utils.sleep(Utils.randomDelay(...GLOBAL_CONFIG.answerDelaySingle)); break; case 'multi': await this.answerMulti(questionEl, match.answer); await Utils.sleep(Utils.randomDelay(...GLOBAL_CONFIG.answerDelaySingle)); break; case 'judge': await this.answerJudge(questionEl, match.answer); await Utils.sleep(Utils.randomDelay(...GLOBAL_CONFIG.answerDelaySingle)); break; case 'fill': await this.answerFill(questionEl, match.answer); await Utils.sleep(Utils.randomDelay(...GLOBAL_CONFIG.answerDelayFill)); break; } }, matchBank(questionText) { let best = null; let bestScore = 0; for (const item of GLOBAL_CONFIG.questionBank) { const score = Utils.similarity(questionText, item.question); if (score > bestScore) { bestScore = score; best = item; } } return bestScore >= 0.78 ? best : null; }, async answerSingle(el, answer) { const options = el.querySelectorAll(SELECTORS.optionSingle); for (const opt of options) { if (opt.textContent.trim().includes(answer.trim())) { await Utils.humanMoveTo(opt); opt.click(); return; } } }, async answerMulti(el, answer) { const answers = answer.split(/[,,、]/).map(s => s.trim()); const options = el.querySelectorAll(SELECTORS.optionMulti); for (const opt of options) { const text = opt.textContent.trim(); if (answers.some(a => text.includes(a))) { await Utils.humanMoveTo(opt); opt.click(); await Utils.sleep(350); } } }, async answerJudge(el, answer) { const isTrue = answer.includes('正确') || answer.includes('对') || answer.includes('√'); const selector = isTrue ? SELECTORS.judgeTrue : SELECTORS.judgeFalse; const btn = el.querySelector(selector); if (btn) { await Utils.humanMoveTo(btn); btn.click(); } }, async answerFill(el, answer) { const input = el.querySelector(SELECTORS.fillInput); if (input) { await Utils.humanMoveTo(input); input.focus(); input.value = answer; input.dispatchEvent(new Event('input', { bubbles: true })); input.dispatchEvent(new Event('change', { bubbles: true })); } } }; // ------------------------------ 悬浮控制面板(拖拽+日志+状态) ------------------------------ const UI = { panel: null, logBox: null, statusText: null, courseText: null, logExpanded: false, init() { this.createPanel(); this.bindDrag(); AntiCheat.init(); }, createPanel() { const panel = document.createElement('div'); panel.id = 'auto-study-panel'; panel.style.cssText = ` position: fixed; top: 100px; right: 20px; z-index: 2147483647; width: 300px; background: #ffffff; border-radius: 10px; box-shadow: 0 6px 20px rgba(0,0,0,0.18); font-family: "Microsoft YaHei", "PingFang SC", sans-serif; font-size: 13px; user-select: none; overflow: hidden; border: 1px solid #e5e7eb; `; panel.innerHTML = `