仅供参考需要会代码#!/usr/bin/env python # -*- coding: utf-8 -*- 自动刷课脚本 - 连续nodeId模式 功能按nodeId连续递增播放视频从起始ID播放到结束ID 视频时长固定为16分钟 import requests import time import json import re import sys import ddddocr # 配置区域 # 请在这里填写您的完整Cookie COOKIE tokensid.mox88nl692lGUfL62UlMiOvlmjFI4C; __root_domain_v.leykeji.com; _qddazQD.226976319675740; _qdda3-1.1; _qddab3-ezjvz0.mo12vdsk # 课程相关ID COURSE_ID 1011725 CHAPTER_ID 1095185 # 要播放的nodeId范围 START_NODE_ID 1432744 END_NODE_ID 1432772 # 视频时长固定为16分钟960秒 VIDEO_DURATION 960 # 16分钟 960秒 # 播放速度控制秒/帧数值越小越快建议0.8-1.0 PLAY_SPEED 0.85 # 上报间隔秒 REPORT_INTERVAL 30 # 请求头 HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Accept: application/json, text/javascript, */*; q0.01, Accept-Language: zh-CN,zh;q0.9, Content-Type: application/x-www-form-urlencoded; charsetUTF-8, X-Requested-With: XMLHttpRequest, Origin: https://cqcst.leykeji.com, Referer: https://cqcst.leykeji.com/user/course, Cookie: COOKIE, } # API地址 STUDY_URL https://cqcst.leykeji.com/user/node/study NODE_PAGE_URL https://cqcst.leykeji.com/user/node CODE_URL https://cqcst.leykeji.com/service/code class SequentialStudyBot: def __init__(self): self.session requests.Session() self.session.headers.update(HEADERS) # 初始化验证码识别器 try: self.ocr ddddocr.DdddOcr() print(✓ 验证码识别器加载成功) except Exception as e: print(f⚠️ 验证码识别器加载失败: {e}将使用手动输入) self.ocr None # 状态变量 self.study_id 0 self.current_time 0 self.reported_time 0 def solve_captcha(self): 自动识别或手动输入验证码 if not self.ocr: return input( 请手动输入验证码: ).strip() try: # 获取验证码图片 timestamp int(time.time() * 1000) img_url f{CODE_URL}?r{timestamp} response self.session.get(img_url, timeout10) if response.status_code ! 200: print( 获取验证码失败) return input( 请手动输入验证码: ).strip() # 识别验证码 captcha_text self.ocr.classification(response.content) print(f 自动识别验证码: {captcha_text}) if len(captcha_text) 3: return captcha_text else: return input(f 识别结果{captcha_text}异常请手动输入: ).strip() except Exception as e: print(f 验证码识别失败: {e}) return input( 请手动输入验证码: ).strip() def init_study(self, node_id): 初始化学习会话 print(f 初始化学习会话...) data { nodeId: node_id, studyId: 0, studyTime: 1 } try: response self.session.post(STUDY_URL, datadata, timeout10) result response.json() if result.get(status): self.study_id result.get(studyId, 0) print(f ✓ studyId: {self.study_id}) return True else: error_msg result.get(msg, 未知错误) print(f ✗ 初始化失败: {error_msg}) if result.get(need_code): print( 需要验证码尝试处理...) return self.handle_captcha(node_id, 1) return False except Exception as e: print(f ✗ 初始化异常: {e}) return False def handle_captcha(self, node_id, study_time): 处理验证码 captcha self.solve_captcha() if not captcha: return False data { nodeId: node_id, studyId: 0, studyTime: str(study_time), code: captcha } try: response self.session.post(STUDY_URL, datadata, timeout10) result response.json() if result.get(status): self.study_id result.get(studyId, 0) print(f ✓ 验证通过studyId: {self.study_id}) return True else: print(f ✗ 验证失败: {result.get(msg, )}) return False except Exception as e: print(f ✗ 请求异常: {e}) return False def report_progress(self, node_id, study_time): 上报学习进度 data { nodeId: node_id, studyId: str(self.study_id), studyTime: str(study_time) } try: response self.session.post(STUDY_URL, datadata, timeout10) result response.json() if result.get(need_code): print(f ⚠️ 触发验证码正在处理...) if self.handle_captcha(node_id, study_time): return self.report_progress(node_id, study_time) return False if result.get(status): if result.get(studyId): self.study_id result.get(studyId) self.reported_time study_time return True else: print(f ✗ 上报失败: {result.get(msg, 未知错误)}) return False except Exception as e: print(f ✗ 上报异常: {e}) return False def watch_video(self, node_id): 观看单个视频 - 固定16分钟 print(f\n{ * 60}) print(f 开始播放视频 - Node ID: {node_id}) # 使用固定的16分钟时长 duration VIDEO_DURATION print(f⏱️ 视频时长: {duration}秒 (16分钟)) print(f{ * 60}) # 初始化 self.study_id 0 self.current_time 0 self.reported_time 0 if not self.init_study(node_id): print(f ✗ 初始化失败跳过此视频) return False # 计算上报时间点 report_points [1] point REPORT_INTERVAL while point duration: report_points.append(point) point REPORT_INTERVAL if report_points[-1] ! duration: report_points.append(duration) print(f 上报计划: 共{len(report_points)}次) if len(report_points) 10: print(f 上报节点: {report_points}) # 模拟播放 start_time time.time() for target in report_points: if target self.current_time: wait target - self.current_time # 逐秒播放 for _ in range(wait): time.sleep(PLAY_SPEED) self.current_time 1 if self.current_time % 15 0 or self.current_time duration: elapsed int(time.time() - start_time) prog self.current_time / duration * 100 remaining int((duration - self.current_time) * PLAY_SPEED) sys.stdout.write( f\r 播放进度: {self.current_time}/{duration} ({prog:.1f}%) | 已用: {elapsed}s | 预计剩余: {remaining}s) sys.stdout.flush() print() # 上报 print(f 上报: {target}s) if not self.report_progress(node_id, target): print(f ✗ 上报失败停止此视频) return False if target duration: print(f\n✅ 视频 {node_id} 完成) return True return True def run(self, start_id, end_id): 批量运行 print(\n * 60) print( 自动刷课脚本 - 连续nodeId模式) print( * 60) print(f播放范围: {start_id} → {end_id}) print(f共 {end_id - start_id 1} 个视频) print(f每个视频时长: 16分钟 (960秒)) print(f播放速度: {1 / PLAY_SPEED:.2f}x) print(f预计总耗时: {(end_id - start_id 1) * 16 / (1 / PLAY_SPEED):.1f} 分钟) print( * 60) success 0 failed [] for node_id in range(start_id, end_id 1): print(f\n{# * 60}) print(f进度: {success len(failed) 1}/{end_id - start_id 1}) print(f统计: 成功{success}, 失败{len(failed)}) print(f{# * 60}) if self.watch_video(node_id): success 1 print(f✅ 成功: {node_id}) else: failed.append(node_id) print(f❌ 失败: {node_id}) time.sleep(5) # 视频间隔 if node_id end_id: print(\n⏸️ 等待3秒后继续下一个视频...) time.sleep(3) # 最终统计 print(\n * 60) print( 刷课完成统计) print( * 60) print(f总视频数: {end_id - start_id 1}) print(f成功: {success}) print(f失败: {len(failed)}) if failed: print(f失败的nodeId: {failed}) print( * 60) def main(): print(\n * 60) print(自动刷课脚本启动) print( * 60) print(提示: 请确保Cookie有效) print(提示: 每个视频固定播放16分钟) print( * 60) bot SequentialStudyBot() print(f\n将播放 nodeId 从 {START_NODE_ID} 到 {END_NODE_ID}) print(f共 {END_NODE_ID - START_NODE_ID 1} 个视频) print(f每个视频播放16分钟总时长约 {(END_NODE_ID - START_NODE_ID 1) * 16} 分钟) confirm input(\n确认开始? (y/n): ).strip().lower() if confirm y: try: bot.run(START_NODE_ID, END_NODE_ID) except KeyboardInterrupt: print(\n\n⚠️ 用户中断程序) except Exception as e: print(f\n❌ 程序异常: {e}) import traceback traceback.print_exc() else: print(已取消) print(\n程序结束按Enter键退出...) input() if __name__ __main__: main()