自贡市专业技术人员继续教育学习平台刷课脚本分享
# 平台情况
上个月有个四川自贡的朋友联系我,说他们在自贡市专业技术人员继续教育学习平台上上网课。网址是 https://zgzj.ylxue.net/ ,这是自贡市人社局专门给专业技术人员做的培训平台。
朋友姓张,在当地一个事业单位做工程管理。他说这两年项目特别多,白天跑现场、协调各方、开会汇报,晚上还得抽时间看那些继续教育课程。什么专业技术人员权益保护、知识产权、还有一些专业技术的课,一门课一两个小时,真的很费时间。
张工跟我吐槽说,现在干什么都要证,继续教育学分不够的话影响职称评审。可是视频内容有的挺水的,念稿子一样,但平台要求必须完整看完才能算学时。他问我能不能弄个脚本,让视频自己跑,他好有时间处理别的事情。
我看了看这个平台,界面做得还算清晰,课程分类明确,每门课分好几个章节。视频播放器是标准的那种,有进度条能拖拽。问题就是播完一节不会自动跳,得手动点下一节,而且长时间不操作还会被踢出去需要重新登录。
# 脚本功能
针对自贡市专业技术人员继续教育学习平台的特点,脚本实现了以下功能:
视频全自动播放,打开课程页面自动开始播放。支持倍速播放,1倍到2倍速可调。自动切换下一章节,检测到视频快播完时自动跳转。防挂机检测模拟,隔段时间模拟鼠标移动。进度智能记录,确保学习记录准确同步。
脚本安装地址:
暂时下架
提示
如需代学,请联系客服,支持闲鱼交易。

微信联系:yizhituziang

QQ联系:2422270452
- img: /img/weixin.jpg
name: 微信联系:yizhituziang
- img: /img/qq.jpg
name: QQ联系:2422270452
# 使用感受
用了一段时间下来,这个平台整体还算稳定。视频加载速度在四川范围内算正常的,偶尔有点卡但不影响。课程内容覆盖面还可以,专业技术、法律法规、职业道德啥都有。
张工说现在脚本跑起来挺顺的,下班前把浏览器打开挂着,第二天来的时候进度条跑满了,中间基本不用管。控制面板设计得挺直观的,能看到当前状态和已完成数量。
有个问题得说一下,平台有些课程带课后测验,这个暂时帮不上忙。另外如果平台要求人脸验证,那还是得自己来。整体来说用脚本比纯手工快多了,张工说省出来的时间可以看看书或者陪陪家人。
# 使用场景
第一种是平时工作繁忙的,像张工那样白天忙项目晚上还要处理杂事。第二种是课程内容之前接触过的,就是要走个流程拿学时的。第三种是想早点刷完早点解脱的,手动看太慢了,开倍速挂机效率高。
# 技术细节
平台用的是通用的在线教育框架,播放器兼容性还可以。脚本通过定时检测video元素状态来判断播放进度,配合课程列表DOM结构找到下一节。
防挂机这块,脚本会生成随机鼠标移动轨迹并模拟点击操作,间隔时间设的比较合理。切换逻辑会遍历课程列表找到下一个未完成的章节。
整体技术方案针对自贡这个平台做了专门适配,稳定性有保障。
# 常见问题
脚本安装地址暂时下架,有需要找页面底部联系方式。
倍速能开多快?建议1.5倍左右,太快了怕视频加载跟不上。
浏览器用什么好?Chrome或Edge最稳,其他浏览器可能有问题。
进度不同步怎么办?刷新重试,平台本身会定时保存学习进度。
课后测验能自动做吗?暂时不支持,题目得自己看。
# 结束语
自贡市专业技术人员继续教育学习平台是四川自贡地区专业技术人员每年都要打交道的。工作本来就忙,还要抽时间刷课确实让人头疼。脚本能帮你省去大部分盯屏幕的时间,张工用了说好,终于不用熬夜刷课了。
# 核心代码
(function() {
'use strict';
const CONFIG = {
siteName: 'zgzj.ylxue.net',
checkInterval: 2600,
switchWait: 3200,
activityGap: 13000,
finishPercent: 90,
storageKey: 'zgzj_autostudy'
};
let runtime = {
enabled: false,
finished: 0,
rate: 1.0,
lastAction: Date.now()
};
function log(msg) {
console.log(`[自贡继续教育] ${msg}`);
}
function initRuntime() {
const saved = localStorage.getItem(CONFIG.storageKey);
if (saved) {
try {
const parsed = JSON.parse(saved);
runtime.enabled = parsed.enabled !== false;
} catch (e) {
runtime.enabled = true;
}
} else {
runtime.enabled = true;
}
if (runtime.enabled) {
log('自贡市专业技术人员继续教育自动学习脚本已启动');
startAutoPlay();
}
buildPanel();
}
function findVideoEl() {
const list = [
'video',
'#video-box video',
'.course-video video',
'.play-video video',
'.video-js video'
];
for (const sel of list) {
const el = document.querySelector(sel);
if (el && el.duration > 0 && el.offsetParent !== null) {
return el;
}
}
return null;
}
function findPlayerWrap() {
const list = [
'#video-box',
'.course-player',
'.play-wrap',
'.video-container'
];
for (const sel of list) {
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 playVid(vid) {
if (!vid) return false;
try {
if (vid.paused) {
const prom = vid.play();
if (prom && prom.catch) {
prom.catch(() => {
vid.muted = true;
vid.play().catch(() => {});
});
}
}
return true;
} catch (e) {
return false;
}
}
function changeRate(vid, rate) {
if (!vid) return;
try {
vid.playbackRate = rate;
runtime.rate = rate;
log(`播放倍速调整为 ${rate}x`);
} catch (e) {
log(`倍速调整失败: ${e.message}`);
}
}
function simulateAction() {
const now = Date.now();
if (now - runtime.lastAction > CONFIG.activityGap) {
const wrap = findPlayerWrap();
const rect = wrap.getBoundingClientRect();
const x = rect.left + Math.random() * rect.width;
const y = rect.top + Math.random() * rect.height;
const moveEv = new MouseEvent('mousemove', {
clientX: x,
clientY: y,
bubbles: true
});
document.dispatchEvent(moveEv);
setTimeout(() => {
const clickEv = new MouseEvent('click', {
clientX: x,
clientY: y,
bubbles: true
});
document.dispatchEvent(clickEv);
}, 700);
runtime.lastAction = now;
log('已模拟用户操作,防挂机检测');
}
}
function locateNextBtn() {
const sels = ['.next-btn', '.btn-next', '.next-chapter', '[class*="next"]'];
for (const sel of sels) {
const btns = document.querySelectorAll(sel);
for (const btn of btns) {
if (btn.offsetParent !== null && !btn.disabled) {
return btn;
}
}
}
return null;
}
function getChapterList() {
return document.querySelectorAll(
'.chapter-item, .course-item, .lesson-item, .section-item'
);
}
function isFinished(item) {
return item.querySelector('.status-done, .finished, .completed') !== null;
}
function isCurrent(item) {
return item.classList.contains('active', 'current');
}
function goNext() {
const btn = locateNextBtn();
if (btn) {
btn.click();
runtime.finished++;
log(`已点击下一节按钮,已完成 ${runtime.finished} 节`);
setTimeout(startAutoPlay, CONFIG.switchWait);
return;
}
const items = getChapterList();
let foundMe = false;
for (const item of items) {
const done = isFinished(item);
const active = isCurrent(item);
if (active) {
foundMe = true;
continue;
}
if (foundMe && !done) {
item.click();
runtime.finished++;
log('已切换到下一个未完成章节');
setTimeout(startAutoPlay, CONFIG.switchWait);
return;
}
}
log('所有章节已完成或未找到更多');
}
function checkVideo() {
const video = findVideoEl();
if (!video) {
setTimeout(checkVideo, CONFIG.checkInterval);
return;
}
if (video.paused && runtime.enabled) {
playVid(video);
}
const progress = getProgress(video);
if (progress >= CONFIG.finishPercent || video.ended) {
log(`当前进度: ${progress.toFixed(1)}%,准备切换下一节`);
goNext();
return;
}
simulateAction();
setTimeout(checkVideo, CONFIG.checkInterval);
}
function startAutoPlay() {
if (!runtime.enabled) return;
setTimeout(checkVideo, 1800);
}
function pauseIt() {
runtime.enabled = false;
localStorage.setItem(CONFIG.storageKey, JSON.stringify({ enabled: false }));
log('脚本已暂停');
refreshPanel();
}
function resumeIt() {
runtime.enabled = true;
localStorage.setItem(CONFIG.storageKey, JSON.stringify({ enabled: true }));
log('脚本已恢复');
startAutoPlay();
refreshPanel();
}
function toggleIt() {
if (runtime.enabled) {
pauseIt();
} else {
resumeIt();
}
}
function setRate(rate) {
const video = findVideoEl();
if (video) {
changeRate(video, rate);
}
runtime.rate = rate;
refreshPanel();
}
function refreshPanel() {
const sEl = document.getElementById('zgzj_status');
const cEl = document.getElementById('zgzj_count');
const rEl = document.getElementById('zgzj_rate');
if (sEl) sEl.textContent = runtime.enabled ? '运行中' : '已暂停';
if (cEl) cEl.textContent = runtime.finished;
if (rEl) rEl.textContent = runtime.rate;
}
function buildPanel() {
const exist = document.getElementById('zgzj_panel');
if (exist) return;
const panel = document.createElement('div');
panel.id = 'zgzj_panel';
panel.style.cssText = `
position: fixed;
top: 200px;
right: 20px;
background: linear-gradient(135deg, #0c3483 0%, #a2b6df 100%);
color: white;
padding: 14px 16px;
border-radius: 10px;
box-shadow: 0 3px 12px rgba(0,0,0,0.25);
z-index: 999999;
font-size: 13px;
min-width: 170px;
`;
panel.innerHTML = `
<div style="font-weight: bold; margin-bottom: 10px; font-size: 14px;">
自贡继续教育自动学习
</div>
<div style="margin-bottom: 6px;">状态: <span id="zgzj_status">${runtime.enabled ? '运行中' : '已暂停'}</span></div>
<div style="margin-bottom: 6px;">已完成: <span id="zgzj_count">${runtime.finished}</span> 节</div>
<div style="margin-bottom: 10px;">倍速: <span id="zgzj_rate">${runtime.rate}</span>x</div>
<div style="display: flex; gap: 6px; flex-wrap: wrap;">
<button onclick="window.toggleZgzj()" style="
padding: 5px 10px;
border: none;
border-radius: 5px;
cursor: pointer;
background: rgba(255,255,255,0.25);
color: white;
font-size: 12px;
">${runtime.enabled ? '暂停' : '开始'}</button>
<button onclick="window.setZgzjRate(1.0)" style="
padding: 5px 10px;
border: none;
border-radius: 5px;
cursor: pointer;
background: rgba(255,255,255,0.25);
color: white;
font-size: 12px;
">1x</button>
<button onclick="window.setZgzjRate(1.5)" style="
padding: 5px 10px;
border: none;
border-radius: 5px;
cursor: pointer;
background: rgba(255,255,255,0.25);
color: white;
font-size: 12px;
">1.5x</button>
</div>
`;
document.body.appendChild(panel);
window.toggleZgzj = toggleIt;
window.setZgzjRate = setRate;
setInterval(refreshPanel, 1000);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initRuntime);
} else {
initRuntime();
}
})();