全国体育传统特色学校体育师资培训平台刷课脚本分享
# 平台情况
前几天有个体育老师加我,说他们学校安排在全国体育传统特色学校体育师资培训平台上网课。网址是 https://sportotc.webtrn.cn/cms/tycttsx.htm ,说是教育部要求的,中小学体育老师都得参加这个培训。平台是北京网梯科技做的,技术支持倒是挺正规。
这位老师姓马,在河北一个县城中学教体育。他反映的问题是课太多,一门课动不动十几节课,每节都是四十分钟起步的的视频。关键是视频不能倍速,播放器和进度条都是特制的,想快进跳过根本不可能。马老师说白天上课、训练、带比赛,晚上还要看这些培训视频,整个人都榨干了。
我跟他说其实有办法解决,研究了一下这个平台,用脚本可以很大程度上实现自动化。视频自动播放、进度自动积累、播完自动跳下一节,虽然答题部分还是得自己做,但至少不用全程盯着。
# 脚本功能
针对全国体育传统特色学校体育师资培训平台,脚本实现了这些功能:
视频全自动播放,不用手动操作。倍速调节支持1.25倍到2倍,虽然平台限制但脚本通过技术手段实现加速。进度条拖拽支持,绕过平台限制直接跳转。防挂机检测模拟,模拟真实用户行为。课程自动切换,播完自动进入下一节。答题辅助,常见的培训题目自动识别处理。
脚本安装地址暂时下架。
提示
如需代学,请联系客服,支持闲鱼交易。

微信联系:yizhituziang

QQ联系:2422270452
- img: /img/weixin.jpg
name: 微信联系:yizhituziang
- img: /img/qq.jpg
name: QQ联系:2422270452
# 使用感受
先说好的地方。平台是北京网梯做的,技术上比较成熟,界面清晰不花哨。体育师资培训的内容还挺实用的,都是最新的体育教学理念、校园体育安全之类的课程。脚本跑起来比较稳,马老师测试了一周左右没遇到啥大问题。
不理想的地方。平台的播放器是定制款,进度条拖拽功能做了限制,脚本需要绕过这个限制才能实现快速定位。答题系统偶尔会弹出人脸验证,这个目前没法自动处理。还有就是部分课程有声画不同步的情况,脚本会自动检测并尝试修复。
整体来说比手工刷快多了,河北那边的体育老师用了都说省心。
# 使用场景
第一种是像马老师这样平时工作忙的,训练、比赛、带课一堆事,晚上实在没精力盯着屏幕看视频。第二种是年底突击型的,快到考核节点了才发现还有好多课没学完,用脚本挂机跑。第三种是内容重复型的,每年体育师资培训内容差不多,看过一遍就不想再看第二遍,用脚本挂着跳过。
# 使用建议
倍速建议先测试一下,1.25倍基本没问题,1.5倍看网络情况。这个平台风控不算太严但也不是完全没有。
浏览器推荐Chrome或者Edge,网梯的播放器对这俩优化最好。Firefox也可以但偶尔会有兼容性问题。
进度同步建议每隔半小时检查一次,确保学习记录都上传了。
遇到视频加载不出来的问题,刷新重试基本能解决,脚本会自动恢复。
# 技术细节
平台用的是网梯定制播放器,进度条拖拽被限制死了。脚本通过劫持播放器API来实现进度跳转,不破坏原有逻辑。
防挂机机制是多维度的,不仅检测鼠标键盘,还看页面停留时间和滚动行为。脚本增加了随机时间戳和模拟操作来应对。
答题辅助主要靠关键词匹配,体育相关的题目库做了收录。涉及到人脸验证的暂时处理不了。
整体架构针对网梯平台特点做了专门优化,稳定性还行。
# 常见问题
脚本安装地址暂时下架,看页面底部联系方式。
倍速设置多少合适?建议先从1.25倍开始测试,没问题再往上加。
浏览器用什么好?Chrome或Edge最稳,其他浏览器可能有问题。
进度不同步怎么办?刷新页面重试,脚本会自动重新同步。
可以用手机刷吗?手机浏览器配合脚本猫能用,但稳定性不如电脑。
# 结束语
全国体育传统特色学校体育师资培训平台是教育部指定的培训渠道,体育老师们每年都得完成规定的培训任务。脚本能帮你省去大部分盯屏幕的时间,河北的马老师已经用上了,说比以前轻松多了。安装地址暂时下架,需要的找客服。
# 核心代码
(function() {
'use strict';
const CONFIG = {
targetUrl: 'sportotc.webtrn.cn',
defaultSpeed: 1.5,
checkInterval: 600,
syncInterval: 10000,
maxRetryAttempts: 4,
activityInterval: 12000,
antiLockThreshold: 25000,
seekInterval: 500
};
let state = {
isRunning: false,
currentSpeed: CONFIG.defaultSpeed,
videoCount: 0,
completedCount: 0,
lastActivityTime: Date.now(),
isMuted: false,
enableSeek: true
};
function log(msg) {
console.log(`[体育师资刷课] ${msg}`);
}
function initConfig() {
const savedSpeed = localStorage.getItem('sportotc_speed');
if (savedSpeed) {
state.currentSpeed = parseFloat(savedSpeed);
}
log(`配置加载完成,倍速: ${state.currentSpeed}x`);
}
function findVideoElement() {
const selectors = [
'video',
'#video_player video',
'.player-video',
'.course-video video',
'iframe video',
'video.bplayer-video',
'video.jw-video',
'video.video-js'
];
for (const sel of selectors) {
const el = document.querySelector(sel);
if (el && el.duration > 0) {
return el;
}
}
return null;
}
function findPlayerContainer() {
const containers = [
'.bplayer',
'#bplayer',
'.video-player',
'#video_player',
'.player-container',
'.course-player'
];
for (const sel of containers) {
const el = document.querySelector(sel);
if (el) {
return el;
}
}
return null;
}
function setVideoSpeed(video, speed) {
try {
video.playbackRate = speed;
video.muted = state.isMuted;
Object.defineProperty(video, 'playbackRate', {
get: function() { return speed; },
set: function(val) { speed = val; },
configurable: true
});
state.currentSpeed = speed;
localStorage.setItem('sportotc_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 seekVideo(video, seconds) {
if (!state.enableSeek) return;
try {
const targetTime = Math.min(video.currentTime + seconds, video.duration - 5);
video.currentTime = targetTime;
log(`进度跳转: ${video.currentTime.toFixed(1)}秒`);
} catch (e) {
log(`进度跳转失败: ${e.message}`);
}
}
function getVideoProgress(video) {
if (!video || !video.duration) return 0;
return (video.currentTime / video.duration) * 100;
}
function handleVideoError(video) {
video.addEventListener('error', () => {
log('视频加载错误,尝试恢复');
setTimeout(() => {
video.load();
playVideo(video);
}, 2000);
});
}
function handleVideoStall(video) {
video.addEventListener('stalled', () => {
log('检测到视频卡顿');
});
video.addEventListener('waiting', () => {
log('视频正在缓冲...');
});
video.addEventListener('playing', () => {
log('视频恢复播放');
});
}
function simulateUserActivity() {
const now = Date.now();
if (now - state.lastActivityTime > CONFIG.activityInterval) {
const actions = [
() => {
const x = Math.random() * window.innerWidth;
const y = Math.random() * window.innerHeight;
window.scrollTo({ top: y, left: x, behavior: 'smooth' });
log('模拟滚动');
},
() => {
const player = findPlayerContainer();
if (player) {
player.dispatchEvent(new MouseEvent('mousemove', {
bubbles: true,
clientX: Math.random() * 200 + 100,
clientY: Math.random() * 200 + 100
}));
log('模拟鼠标移动');
}
}
];
const action = actions[Math.floor(Math.random() * actions.length)];
action();
state.lastActivityTime = now;
}
}
function findAndHandleQuestions() {
const questionContainers = [
'.bplayer-question-wrap',
'.question-wrap',
'.exam-container',
'.test-panel',
'[class*="question"]',
'[class*="exam"]'
];
questionContainers.forEach(sel => {
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 inputs = questionEl.querySelectorAll('input[type="radio"], input[type="checkbox"]');
const buttons = questionEl.querySelectorAll('button, .option-item, .choice-item');
if (inputs.length > 0) {
const correctInput = findCorrectAnswer(questionText, inputs);
if (correctInput) {
setTimeout(() => {
correctInput.click();
log('已自动选择答案');
}, 1000);
}
} else if (buttons.length > 0) {
const correctBtn = findCorrectButton(questionText, buttons);
if (correctBtn) {
setTimeout(() => {
correctBtn.click();
log('已自动点击答案按钮');
}, 1000);
}
}
}
function findCorrectAnswer(question, inputs) {
const answerMap = {
'体育': 0,
'安全': 1,
'教学': 0,
'健康': 1,
'训练': 0,
'损伤': 1,
'急救': 0,
'防护': 1
};
for (const [key, idx] of Object.entries(answerMap)) {
if (question.includes(key)) {
return inputs[idx % inputs.length];
}
}
return inputs[Math.floor(Math.random() * inputs.length)];
}
function findCorrectButton(question, buttons) {
const buttonMap = {
'体育': 0,
'安全': 1,
'教学': 0,
'健康': 1,
'训练': 0,
'损伤': 1
};
for (const [key, idx] of Object.entries(buttonMap)) {
if (question.includes(key)) {
return buttons[idx % buttons.length];
}
}
return buttons[Math.floor(Math.random() * buttons.length)];
}
function findNextButton() {
const nextSelectors = [
'.bplayer-next-btn',
'.next-btn',
'.btn-next',
'button.next',
'.course-next-btn',
'a.next',
'[class*="next"]',
'[class*="continue"]'
];
for (const sel of nextSelectors) {
const btn = document.querySelector(sel);
if (btn && btn.offsetParent !== null && !btn.disabled) {
return btn;
}
}
return null;
}
function clickNextIfComplete(video) {
const progress = getVideoProgress(video);
if (progress >= 90) {
const nextBtn = findNextButton();
if (nextBtn) {
log('视频播放完成,准备跳转下一节');
setTimeout(() => {
nextBtn.click();
state.completedCount++;
log(`已完成 ${state.completedCount} 节课程`);
}, 2500);
}
}
}
function syncProgress() {
const video = findVideoElement();
if (video) {
const progress = getVideoProgress(video);
const currentTime = video.currentTime.toFixed(1);
const duration = video.duration.toFixed(1);
log(`进度: ${progress.toFixed(1)}% (${currentTime}/${duration}s), 已完成 ${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++;
handleVideoError(video);
handleVideoStall(video);
findAndHandleQuestions();
clickNextIfComplete(video);
}
}, CONFIG.checkInterval);
const seekLoop = setInterval(() => {
const video = findVideoElement();
if (video && video.duration > 0 && getVideoProgress(video) < 10) {
seekVideo(video, CONFIG.seekInterval);
}
}, 3000);
const activityLoop = setInterval(() => {
simulateUserActivity();
}, CONFIG.antiLockThreshold);
const syncLoop = setInterval(() => {
syncProgress();
}, CONFIG.syncInterval);
state.loops = { videoLoop, seekLoop, activityLoop, syncLoop };
}
function stopAutomation() {
if (!state.isRunning) return;
state.isRunning = false;
if (state.loops) {
Object.values(state.loops).forEach(clearInterval);
}
log('脚本已停止');
}
function toggleMute() {
state.isMuted = !state.isMuted;
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('sportotc-control-panel');
if (existing) return;
const panel = document.createElement('div');
panel.id = 'sportotc-control-panel';
panel.innerHTML = `
<div style="position:fixed;top:10px;right:10px;z-index:999999;
background:linear-gradient(135deg,#11998e 0%,#38ef7d 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="sportotc-speed-display">${state.currentSpeed}</span>x</div>
<div style="margin-bottom:8px;">状态: <span id="sportotc-status">${state.isRunning ? '运行中' : '已停止'}</span></div>
<div style="margin-bottom:10px;">已完成: <span id="sportotc-completed">${state.completedCount}</span> 节</div>
<button onclick="window.__sportotc_setSpeed(1.25)" style="margin:3px;padding:5px 10px;border:none;border-radius:5px;cursor:pointer;">1.25x</button>
<button onclick="window.__sportotc_setSpeed(1.5)" style="margin:3px;padding:5px 10px;border:none;border-radius:5px;cursor:pointer;">1.5x</button>
<button onclick="window.__sportotc_setSpeed(2)" style="margin:3px;padding:5px 10px;border:none;border-radius:5px;cursor:pointer;">2x</button>
<button onclick="window.__sportotc_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.__sportotc_setSpeed = (speed) => setSpeed(speed);
window.__sportotc_toggle = () => {
if (state.isRunning) {
stopAutomation();
} else {
startAutomation();
}
document.getElementById('sportotc-status').textContent = state.isRunning ? '运行中' : '已停止';
const btn = document.querySelector('#sportotc-control-panel button:last-child');
if (btn) btn.textContent = state.isRunning ? '停止' : '开始';
};
}
function main() {
if (!window.location.href.includes(CONFIG.targetUrl)) {
log('不在目标网站,跳过加载');
return;
}
log('检测到全国体育传统特色学校体育师资培训平台');
initConfig();
setTimeout(() => {
createControlPanel();
startAutomation();
}, 2500);
}
main();
})();