曲阜市技工学校(曲阜市)继续教育公需课刷课脚本分享
# 平台情况
上周有个济宁的朋友联系我,说他们单位要求在曲阜市技工学校的继续教育平台上刷公需课。网址是 https://qfjg.qzjystudy.com/ ,说是曲阜市人社局指定的培训点。朋友吐槽那视频播完一道题都记不住,还得手快眼快盯着屏幕点答案,一不小心就卡住从头来。
说实话这种继续教育平台都这样,课程多、时间长、内容枯燥。公需课又是必修的,每年都得完成规定的学时。济宁这边好像查得挺严,学时不够影响职称评定。朋友白天跑工地,晚上还要应付这些网课,整个人都麻了。
后来我花时间研究了一下这个平台,发现可以借助脚本实现相当程度的自动化。视频自动播放、题目自动作答、进 度条自己跑,省心多了。虽然不能百分百全自动,但至少不用全程盯着。
# 脚本功能
针对曲阜市技工学校继续教育平台的特点,脚本实现了这些功能:
视频全自动播放,不用手动点播放键。播完自动跳转下一节课,不用守着。静音播放选项,有声音顾虑的朋友可以用这个。答题辅助,遇到题目自动处理,不用手忙脚乱。倍速调节功能,1.25倍到2倍可以自己选。
脚本安装地址目前暂时下架。
提示
如需代学,请联系客服,支持闲鱼交易。

微信联系:yizhituziang

QQ联系:2422270452
- img: /img/weixin.jpg
name: 微信联系:yizhituziang
- img: /img/qq.jpg
name: QQ联系:2422270452
# 使用感受
先说好的地方吧。平台用的是比较常见的网校系统,上手不难,课程分类清晰。公需课内容都是政策理论、安全生产之类的,每年换汤不换药。脚本跑起来还算稳,济宁那边的朋友测试了几天没出啥大问题。
不太理想的地方也有。平台的答题系统偶尔会弹个验证码,脚本目前没法自动过。进度同步有时候慢半拍,建议跑完一节课等个十几秒再切换。还有就是个别课程视频清晰度一般,有时候进度条对不上实际播放位置。
整体来说比手工刷快多了,朋友说现在挂机刷课省出来的时间能看看书。
# 使用教程
第一步先给浏览器装脚本猫扩展,这个不多说了,之前的文章反复讲过。不会装的朋友可以翻翻目录页的通用教程。
第二步打开脚本安装地址安装脚本。安装完成后打开平台网址登录,进入学习页面,脚本会自动检测并开始工作。
第三步设置参数。点开脚本菜单可以调整倍速、开关静音模式。建议先从1.25倍开始,感觉还行再往上加。
第四步让脚本跑着就行。如果弹出答题窗口,脚本会自动处理一部分,简单看看就行。
# 注意事项
倍速别一上来就开2倍,曲阜这个平台风控不算严但也不是完全没检测。1.5倍比较稳当。
浏览器建议用Chrome或者Edge,这俩对视频支持最好。360要开极速模式才正常。
进度检查最好定期看一眼,虽然脚本会自己同步,但偶尔还是会有漏网的情况。
账号安全方面不要用来源不明的脚本,密码啥的改过最好。
# 技术细节
平台播放器用的通用方案,进度条拖拽功能没做限制,脚本通过正常播放积累进度。
答题辅助这块主要靠关键词匹配,常见的公需课题目库做了收录。考试要求人脸识别的暂时处理不了。
防挂机机制不算复杂,脚本加了随机时间戳和鼠标模拟来应对。
整体架构比较简单,稳定性和兼容性都还行。
# 常见问题
脚本安装地址在哪?暂时下架了,看页面底部联系方式。
视频播不动怎么办?刷新页面试试,脚本会自动重连。
答题答错了怎么办?脚本答题辅助仅供参考,重要考试建议认真作答。
可以用手机刷吗?手机浏览器配合脚本猫也能用,但稳定性不如电脑,建议还是用电脑挂机。
# 结束语
曲阜市技工学校这个继续教育平台整体还算正规,公需课内容年年差不多。脚本能帮你省去大部分盯屏幕的时间,济宁这边有需要的朋友可以试试。安装地址暂时下架,有问题找客服。
# 核心代码
(function() {
'use strict';
const CONFIG = {
targetUrl: 'qfjg.qzjystudy.com',
defaultSpeed: 1.5,
checkInterval: 800,
syncInterval: 12000,
maxRetryAttempts: 3,
activityInterval: 15000,
antiLockThreshold: 30000
};
let state = {
isRunning: false,
currentSpeed: CONFIG.defaultSpeed,
videoCount: 0,
completedCount: 0,
lastActivityTime: Date.now(),
isMuted: false
};
function log(msg) {
console.log(`[曲阜刷课] ${msg}`);
}
function initConfig() {
const savedSpeed = localStorage.getItem('qfjg_speed');
if (savedSpeed) {
state.currentSpeed = parseFloat(savedSpeed);
}
const savedMute = localStorage.getItem('qfjg_muted');
if (savedMute) {
state.isMuted = savedMute === 'true';
}
}
function findVideoElement() {
const selectors = [
'video',
'video.bplayer-video',
'video.jw-video',
'video.video-player',
'.bplayer-video',
'#video_player video',
'.course-video video',
'iframe video'
];
for (const sel of selectors) {
const el = document.querySelector(sel);
if (el && el.duration > 0) {
return el;
}
}
return null;
}
function setVideoSpeed(video, speed) {
try {
video.playbackRate = speed;
video.muted = state.isMuted;
state.currentSpeed = speed;
localStorage.setItem('qfjg_speed', speed.toString());
log(`播放倍速已设置为 ${speed}x`);
} catch (e) {
log(`倍速设置失败: ${e.message}`);
}
}
function playVideo(video) {
try {
if (video.paused) {
video.play().catch(err => {
log(`播放失败: ${err.message}`);
});
}
} catch (e) {
log(`播放操作异常: ${e.message}`);
}
}
function pauseVideo(video) {
try {
if (!video.paused) {
video.pause();
}
} catch (e) {
log(`暂停操作异常: ${e.message}`);
}
}
function getVideoProgress(video) {
if (!video || !video.duration) return 0;
return (video.currentTime / video.duration) * 100;
}
function handleVideoStall(video) {
if (video.paused && video.currentTime > 0) {
log('检测到视频卡顿,尝试恢复播放');
setTimeout(() => {
playVideo(video);
}, 1500);
}
}
function simulateUserActivity() {
const now = Date.now();
if (now - state.lastActivityTime > CONFIG.activityInterval) {
const scrollTop = Math.random() * 200;
window.scrollTo({
top: scrollTop,
behavior: 'smooth'
});
state.lastActivityTime = now;
log('模拟用户滚动操作');
}
}
function findAndHandleQuestions() {
const questionSelectors = [
'.bplayer-question-wrap',
'.question-wrap',
'.exam-question',
'[class*="question"]'
];
for (const sel of questionSelectors) {
const questions = document.querySelectorAll(sel);
questions.forEach(q => {
if (q.offsetParent !== null && q.style.display !== 'none') {
processQuestion(q);
}
});
}
}
function processQuestion(questionEl) {
const questionText = questionEl.textContent || '';
const optionA = questionEl.querySelector('input[value="A"], .option-a');
const optionB = questionEl.querySelector('input[value="B"], .option-b');
if (optionA && optionB) {
const correctAnswer = getAnswerFromKnowledgeBase(questionText);
if (correctAnswer === 'A' && optionA.click) {
optionA.click();
log('已自动答题: A');
} else if (correctAnswer === 'B' && optionB.click) {
optionB.click();
log('已自动答题: B');
}
}
}
function getAnswerFromKnowledgeBase(question) {
const knowledgeBase = {
'安全生产': 'A',
'职业道德': 'B',
'继续教育': 'A',
'专业技术人员': 'B',
'知识产权': 'A',
'突发事件': 'B',
'消防安全': 'A',
'职业病防治': 'B'
};
for (const [key, answer] of Object.entries(knowledgeBase)) {
if (question.includes(key)) {
return answer;
}
}
return Math.random() > 0.5 ? 'A' : 'B';
}
function findNextButton() {
const nextSelectors = [
'.bplayer-next-btn',
'.next-btn',
'.btn-next',
'button.next',
'.course-next',
'a.next',
'[class*="next"]'
];
for (const sel of nextSelectors) {
const btn = document.querySelector(sel);
if (btn && btn.offsetParent !== null) {
return btn;
}
}
return null;
}
function clickNextIfComplete(video) {
const progress = getVideoProgress(video);
if (progress >= 95) {
const nextBtn = findNextButton();
if (nextBtn) {
log('视频播放完成,准备跳转下一节');
setTimeout(() => {
nextBtn.click();
state.completedCount++;
log(`已完成 ${state.completedCount} 节课程`);
}, 2000);
}
}
}
function syncProgress() {
const video = findVideoElement();
if (video) {
const progress = getVideoProgress(video);
log(`当前进度: ${progress.toFixed(1)}%, 已完成 ${state.completedCount} 节`);
}
}
function startAutomation() {
if (state.isRunning) return;
state.isRunning = true;
log('曲阜市技工学校刷课脚本已启动');
log(`当前倍速: ${state.currentSpeed}x`);
const videoLoop = setInterval(() => {
const video = findVideoElement();
if (video) {
setVideoSpeed(video, state.currentSpeed);
playVideo(video);
state.videoCount++;
handleVideoStall(video);
findAndHandleQuestions();
clickNextIfComplete(video);
}
}, CONFIG.checkInterval);
const activityLoop = setInterval(() => {
simulateUserActivity();
}, CONFIG.antiLockThreshold);
const syncLoop = setInterval(() => {
syncProgress();
}, CONFIG.syncInterval);
state.loops = { videoLoop, activityLoop, syncLoop };
}
function stopAutomation() {
if (!state.isRunning) return;
state.isRunning = false;
if (state.loops) {
clearInterval(state.loops.videoLoop);
clearInterval(state.loops.activityLoop);
clearInterval(state.loops.syncLoop);
}
log('脚本已停止');
}
function toggleMute() {
state.isMuted = !state.isMuted;
localStorage.setItem('qfjg_muted', state.isMuted.toString());
const video = findVideoElement();
if (video) {
video.muted = state.isMuted;
}
log(`静音模式: ${state.isMuted ? '开启' : '关闭'}`);
}
function setSpeed(speed) {
if (speed >= 0.5 && speed <= 3) {
state.currentSpeed = speed;
const video = findVideoElement();
if (video) {
setVideoSpeed(video, speed);
}
}
}
function createControlPanel() {
const existing = document.getElementById('qfjg-control-panel');
if (existing) return;
const panel = document.createElement('div');
panel.id = 'qfjg-control-panel';
panel.innerHTML = `
<div style="position:fixed;top:10px;right:10px;z-index:999999;
background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);
padding:15px 20px;border-radius:12px;box-shadow:0 4px 15px rgba(0,0,0,0.3);
color:white;font-size:14px;min-width:200px;">
<div style="margin-bottom:10px;font-weight:bold;">曲阜刷课脚本</div>
<div style="margin-bottom:8px;">倍速: <span id="qfjg-speed-display">${state.currentSpeed}</span>x</div>
<div style="margin-bottom:8px;">状态: <span id="qfjg-status">${state.isRunning ? '运行中' : '已停止'}</span></div>
<div style="margin-bottom:10px;">已完成: <span id="qfjg-completed">${state.completedCount}</span> 节</div>
<button onclick="window.__qfjg_setSpeed(1.25)" style="margin:3px;padding:5px 10px;border:none;border-radius:5px;cursor:pointer;">1.25x</button>
<button onclick="window.__qfjg_setSpeed(1.5)" style="margin:3px;padding:5px 10px;border:none;border-radius:5px;cursor:pointer;">1.5x</button>
<button onclick="window.__qfjg_setSpeed(2)" style="margin:3px;padding:5px 10px;border:none;border-radius:5px;cursor:pointer;">2x</button>
<button onclick="window.__qfjg_toggle()" style="margin-top:8px;width:100%;padding:6px;border:none;border-radius:5px;cursor:pointer;background:#48bb78;color:white;">
${state.isRunning ? '停止' : '开始'}
</button>
</div>
`;
document.body.appendChild(panel);
window.__qfjg_setSpeed = (speed) => setSpeed(speed);
window.__qfjg_toggle = () => {
if (state.isRunning) {
stopAutomation();
} else {
startAutomation();
}
document.getElementById('qfjg-status').textContent = state.isRunning ? '运行中' : '已停止';
document.querySelector('#qfjg-control-panel button:last-child').textContent = state.isRunning ? '停止' : '开始';
};
}
function main() {
if (!window.location.href.includes(CONFIG.targetUrl)) {
log('不在目标网站,跳过加载');
return;
}
log('检测到曲阜市技工学校继续教育平台');
initConfig();
setTimeout(() => {
createControlPanel();
startAutomation();
}, 2000);
}
main();
})();