滁州市专业技术人员继续教育刷课脚本分享
# 平台情况
滁州市专业技术人员继续教育网络培训平台,网址 https://chuzhou.huilearning.com/ ,安徽滁州这边做专技培训的应该都知道。需要学专业科目和转岗培训的学员,得根据地市或行业主管单位的要求来选课。
上个月天长的小陈微信联系我,说他被这个平台折腾得够呛。小陈在天长一家电子厂做技术员,厂里要求今年底之前必须完成多少学时。他跟我讲,这个平台登录倒是挺方便的,账号密码输进去就行,但进去之后问题就来了。课程选好之后,视频一集一集的,每集都得完整看完才能计入学时,关键是播完不会自动跳下一集,得自己手动点。小陈说那天晚上他看着视频打瞌睡,差点睡着了结果视频停在那儿白播。
我上去看了看,界面做得还行,左侧有专业课和转岗培训的分类。视频播放器是通用的,加载速度还行。但有个很烦人的地方,就是长时间不操作会检测你,可能直接踢你下线。还有那个进度条,有时候显示不太准,明明看完了但系统没记录。
对了,这个平台还有个发票的问题,缴完费24小时后才能到学习中心下载电子发票。不过这个跟刷课关系不大,就是顺嘴提一句。
# 脚本功能
针对滁州市专业技术人员继续教育平台的特点,脚本实现了以下功能:
视频自动播放,进入课程页面后自动开始,不用手动点播放按钮。自动切换下一节,检测到视频快播完时自动跳到下一个。防掉线模拟,定期模拟鼠标移动和点击操作,避免被踢下线。倍速调节,1倍到2倍速可选。进度实时显示,控制面板上能看到当前状态和已完成数量。课程列表智能识别,自动跳过已经看完的章节。
脚本安装地址: 暂时下架
# 代学服务
提示
如需代学,请联系客服,支持闲鱼交易。

微信联系:yizhituziang

QQ联系:2422270452
- img: /img/weixin.jpg
name: 微信联系:yizhituziang
- img: /img/qq.jpg
name: QQ联系:2422270452
# 使用感受
小陈用了差不多两周了,他说比之前好太多了。现在每天下班回来把浏览器挂着,中间吃个饭洗个澡,回来基本任务就跑完了。他说最烦人的那个手动跳转终于不用管了,脚本帮你搞定一切。
有个事得提醒一下,滁州这个平台电脑学习推荐用360安全浏览器极速模式,如果你用Chrome也行,但可能会有些兼容问题。另外有些课程带课后测验或者在线考试,这个脚本帮不了你,得自己做。还有如果你们单位要求人脸验证,那也得自己来。
小陈还说了个细节,他说有时候视频看着看着会突然卡住不动了,这种情况脚本会自动检测到然后尝试重新播放。如果实在卡得不行就刷新一下页面,脚本会从上次的位置继续跑。
# 使用场景
白天上班晚上没精力看视频的,像小陈那样在厂里忙了一天回家就想歇会的。课程内容之前学过的,走个流程拿学时的。想省时间早点刷完的,开个1.5倍速挂着自动跑效率高多了。
# 技术细节
滁州这个平台用的是汇学习系列的框架,界面是单页应用风格。脚本通过定时检测video元素状态来判断播放进度,配合课程列表的DOM结构找到下一节。
防掉线这块比较关键,因为平台对长时间不操作检测比较敏感。脚本会生成随机鼠标移动轨迹,间隔时间也做了随机化处理,不会太规律被系统发现。另外加了视频异常检测,如果视频意外停止会自动尝试恢复播放。
整体方案针对滁州平台做了专门适配,小陈用了两周没出过什么大问题。
# 常见问题
脚本安装地址暂时下架,有需要代学的朋友看页面底部联系方式。
倍速怎么选?建议1.5倍,这个平台服务器还行不会卡,太快了怕加载跟不上。
浏览器用什么好?360安全浏览器开极速模式最稳,Chrome也行但可能有点小问题。
进度没同步怎么办?刷新一下页面,平台会自动保存学习进度。
课后测验能自动做吗?暂时不支持,得自己看题目做。
# 结束语
滁州市专业技术人员继续教育网络培训平台是滁州地区专技人员每年都要用的,小陈之前为了刷课好几个晚上没休息好,用了脚本之后终于不用熬夜了安徽这边的继续教育平台体验都差不多,视频长、不自动跳、容易掉线,脚本能帮你解决大部分问题。需要专业科目或者转岗培训的朋友可以试试,效果还不错。
# 核心代码
(function() {
'use strict';
const CONFIG = {
platform: 'chuzhou.huilearning.com',
scanInterval: 2600,
nextInterval: 3400,
keepAlive: 14000,
finishPercent: 90,
stateKey: 'chuzhou_auto_state'
};
let runtime = {
active: false,
finished: 0,
rate: 1.0,
lastActivity: Date.now(),
pauseCount: 0
};
function log(msg) {
console.log(`[滁州继续教育] ${msg}`);
}
function readState() {
const stored = localStorage.getItem(CONFIG.stateKey);
if (stored) {
try {
const parsed = JSON.parse(stored);
runtime.active = parsed.running !== false;
} catch (e) {
runtime.active = true;
}
} else {
runtime.active = true;
}
}
function writeState() {
localStorage.setItem(CONFIG.stateKey, JSON.stringify({
running: runtime.active,
speed: runtime.rate
}));
}
function start() {
readState();
if (runtime.active) {
log('滁州市专业技术人员继续教育自动学习已启动');
startMonitor();
}
createPanel();
}
function locateVideo() {
const selectors = [
'video',
'#videoPlayer video',
'.course-video video',
'.lesson-video video',
'.video-js video',
'.vjs-tech',
'video.h5-video'
];
for (const sel of selectors) {
const el = document.querySelector(sel);
if (el && el.duration > 0 && el.offsetParent !== null) {
return el;
}
}
return null;
}
function locateContainer() {
const selectors = [
'#videoPlayer',
'.course-player',
'.lesson-container',
'.video-wrapper',
'.player-wrap',
'.h5-player'
];
for (const sel of selectors) {
const el = document.querySelector(sel);
if (el) return el;
}
return document.body;
}
function getProgress(vid) {
if (!vid || !vid.duration) return 0;
return (vid.currentTime / vid.duration) * 100;
}
function triggerPlay(vid) {
if (!vid) return false;
try {
if (vid.paused) {
const promise = vid.play();
if (promise && promise.catch) {
promise.catch(() => {
vid.muted = true;
vid.play().catch(() => {});
});
}
}
return true;
} catch (e) {
return false;
}
}
function setSpeed(vid, multiplier) {
if (!vid) return;
try {
vid.playbackRate = multiplier;
runtime.rate = multiplier;
log(`播放倍速已调整为 ${multiplier}x`);
} catch (e) {
log('倍速设置遇到点问题');
}
}
function simulateActivity() {
const now = Date.now();
if (now - runtime.lastActivity > CONFIG.keepAlive) {
const container = locateContainer();
const box = container.getBoundingClientRect();
const x = box.left + Math.random() * box.width;
const y = box.top + Math.random() * box.height;
const moveEvt = new MouseEvent('mousemove', {
clientX: x, clientY: y, bubbles: true
});
document.dispatchEvent(moveEvt);
setTimeout(() => {
const clickEvt = new MouseEvent('click', {
clientX: x, clientY: y, bubbles: true
});
document.dispatchEvent(clickEvt);
}, 500);
runtime.lastActivity = now;
log('已模拟用户操作,维持会话活跃');
}
}
function locateNextButton() {
const patterns = ['.next-btn', '.btn-next', '.next-lesson', '[class*="next"]', '.next-chapter'];
for (const pattern of patterns) {
const buttons = document.querySelectorAll(pattern);
for (const btn of buttons) {
if (btn.offsetParent !== null && !btn.disabled) {
return btn;
}
}
}
return null;
}
function getChapterList() {
return document.querySelectorAll(
'.chapter-item, .lesson-item, .course-chapter, .section-item, .catalog-item'
);
}
function checkFinished(item) {
return item.querySelector('.finished, .done, .completed, .status-ok') !== null;
}
function checkCurrent(item) {
return item.classList.contains('active') || item.classList.contains('current');
}
function navigateNext() {
const nextBtn = locateNextButton();
if (nextBtn) {
nextBtn.click();
runtime.finished++;
log(`已切换到下一节,完成 ${runtime.finished} 节`);
setTimeout(startMonitor, CONFIG.nextInterval);
return;
}
const items = getChapterList();
let metCurrent = false;
for (const item of items) {
const current = checkCurrent(item);
const done = checkFinished(item);
if (current) {
metCurrent = true;
continue;
}
if (metCurrent && !done) {
item.click();
runtime.finished++;
log('已跳转至下一未完成章节');
setTimeout(startMonitor, CONFIG.nextInterval);
return;
}
}
log('所有章节已完成或未找到更多');
}
function monitorLoop() {
const video = locateVideo();
if (!video) {
runtime.pauseCount++;
if (runtime.pauseCount > 15) {
log('检测不到视频,请确认是否在课程页面');
}
setTimeout(monitorLoop, CONFIG.scanInterval);
return;
}
runtime.pauseCount = 0;
triggerPlay(video);
const progress = getProgress(video);
if (progress >= CONFIG.finishPercent) {
log(`当前视频播放至 ${progress.toFixed(1)}%,准备跳转下一节`);
navigateNext();
return;
}
simulateActivity();
setTimeout(monitorLoop, CONFIG.scanInterval);
}
function buildPanel() {
if (document.getElementById('chuzhou-script-panel')) return;
const panel = document.createElement('div');
panel.id = 'chuzhou-script-panel';
panel.style.cssText = `
position: fixed; top: 120px; right: 20px; width: 220px;
background: #fff; border-radius: 8px; box-shadow: 0 2px 12px rgba(0,0,0,0.15);
padding: 16px; z-index: 99999; font-size: 14px;
`;
panel.innerHTML = `
<div style="font-weight: bold; margin-bottom: 12px; color: #333;">
滁州继续教育自动刷课
</div>
<div style="margin-bottom: 8px;">
<span style="color: #666;">状态:</span>
<span id="chuzhou-status" style="color: #52c41a;">运行中</span>
</div>
<div style="margin-bottom: 8px;">
<span style="color: #666;">完成:</span>
<span id="chuzhou-done" style="color: #1890ff;">0</span> 节
</div>
<div style="margin-bottom: 12px;">
<span style="color: #666;">倍速:</span>
<select id="chuzhou-speed" style="padding: 2px 6px; border-radius: 4px;">
<option value="1">1倍速</option>
<option value="1.5" selected>1.5倍速</option>
<option value="2">2倍速</option>
</select>
</div>
<button id="chuzhou-toggle" style="
width: 100%; padding: 8px; background: #ff4d4f; color: #fff;
border: none; border-radius: 4px; cursor: pointer;
">停止脚本</button>
`;
document.body.appendChild(panel);
document.getElementById('chuzhou-speed').onchange = function() {
runtime.rate = parseFloat(this.value);
const video = locateVideo();
if (video) setSpeed(video, runtime.rate);
writeState();
};
document.getElementById('chuzhou-toggle').onclick = function() {
runtime.active = !runtime.active;
this.textContent = runtime.active ? '停止脚本' : '启动脚本';
this.style.background = runtime.active ? '#ff4d4f' : '#52c41a';
document.getElementById('chuzhou-status').textContent = runtime.active ? '运行中' : '已停止';
document.getElementById('chuzhou-status').style.color = runtime.active ? '#52c41a' : '#999';
writeState();
if (runtime.active) {
log('脚本已重新启动');
startMonitor();
}
};
}
function createPanel() {
buildPanel();
setInterval(() => {
const doneEl = document.getElementById('chuzhou-done');
if (doneEl) doneEl.textContent = runtime.finished;
}, 2000);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', start);
} else {
start();
}
})();