ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

我给学习通做了个「自动学习」系统:云端定时刷 + 本地 exe,全程真实播放、证据可审计

我给学习通做了个「自动学习」系统:云端定时刷 + 本地 exe,全程真实播放、证据可审计 项目地址:https://github.com/Thy985/xuexitong(纯开源,Python Playwright GitHub Actions)技术栈:Playwright / PyInstaller / GitHub Actions / Edge TTS / Remotion写在前面这学期有门选修课,选修课网课 47 集、每集 25 分钟——粗算将近 20 个小时。挂机看吧,网页一休眠进度条就停;市面上的「秒刷」工具吧,原理大多是伪造multimedia/log心跳、改播放进度签名,轻则进度无效,重则账号异常。所以我自己做了一个,思路很克制:只把「挂着」这件事自动化,「看」仍然是真的看——程序用真实浏览器一集集自然播放,服务端怎么判完成,我就怎么认。挂机是它的,知识还是我的(抽查提问时至少进度是真的)。⚠ 边界声明(重要,先立后破)本项目仅做「真实浏览器自然播放 → 服务端完成」:不构造/伪造/重放multimedia/log,不修改enc / attDurationEnc / videoFaceCaptureEnc / playingTime / _t等签名参数;不跳过播放、不倍速、不宣称「一键整门课秒完成」,一次 Run 只自然完成指定任务点;失败如实记录failure_stage,绝不静默伪装成功;同账号严格串行,避免多端并发被风控。请自行评估并遵守所在学校/平台的规则。本文只讲技术与工程,不鼓励任何滥用。效果先上:配置一次后,每天凌晨 00:07 / 02:07 两条 GitHub cron 自动唤醒,逐章推进;或者打包成 Windows exe 双击常驻。下面按「架构 → 上手 → 核心设计 → 打包踩坑」展开。一、整体架构GitHub Actions cron(云端) / 本地 Xuexitong.exe(常驻循环) ↓ Scheduler 决策引擎 (RUN / NOOP / BLOCKED 熔断) ↓ TDVP 探针:逐章读服务端 DOM,刷新任务队列 ↓ Runtime:headed Playwright 真实浏览器播放 ↓ Evidence 证据 Registry 任务账本(每章落盘) ↓ 超星服务端(isPassed 唯一完成真源)仓库分层很传统:app/(运行时入口)、scheduler/(决策)、tvdp/(探针协议)、state/(持久化账本)、utils/(浏览器工厂/滑块验证码/cookie 存储)。测试 500 用例,分 unit / integration / regression(带真实 DOM fixture)三层。两种运行模式共用同一套状态机:云端靠 GitHub cron 冷启动,本地 exe 靠常驻循环(活跃轮 2 分钟、空闲轮 30 分钟),状态文件格式一致,可以错峰双跑(后面讲为什么不用同步)。二、快速上手云端模式(Fork 三步)# 1. Fork 仓库后配 Secretsgh secretsetCX_USER-b手机号gh secretsetCX_PASS-b密码# 2. 配置课程(Actions 页 Run workflow → actioninitialize,粘课程 URL)gh workflow run run.yml-factioninitialize\-fcourse_urlhttps://mooc1.chaoxing.com/mycourse/studentstudy?chapterId…courseId…clazzid…cpi…enc…mooc21hidetype0openc…# 3. 之后 cron 每天自动跑,或手动触发gh workflow run run.yml-factionscheduler课程 URL 必须从浏览器地址栏完整复制:clazzid要小写、openc/hidetype不能丢,否则服务端不渲染视频 iframe(血泪教训,见文末注意事项)。本地模式(双击 exe).venv/Scripts/python.exe build.py# PyInstaller 打包,内置 chromium# 产物 dist/Xuexitong/:双击 Xuexitong.exe → 引导填账号 → 粘课程 URL → 常驻刷课启动向导是「可跳过」式的:展示当前课程与进度,回车即开始;输s换课(旧课归档、进度保留);输数字调本次每轮推进章数。计划任务/管道等非交互场景自动跳过向导,行为完全一致。三、核心设计:为什么它是「稳」的1. 服务端真源(P0-3)——不走本地账本自动学习系统最容易翻车的地方是账本漂移:本地记的「已完成」和服务端认的「已完成」对不上。我的原则是本地 state 只是缓存,超星服务端才是唯一真源:账号首次进入课程,bootstrap_registry_from_server从服务端 catalog 一次性材料化全部任务,progress.completed直接写成服务端已完成数;每轮执行前,TDVP 探针逐章 point-read 服务端 DOM(读.task-item .status完成标记),reconcile 掉本地账本与真实世界的偏差;单章是否 PASS只认服务端isPassed(SERVER_CONFIRMED_PASS),UI 自检的 10/10 只是诊断参考。这个设计还免费送了一个能力:本地 exe 和云端 GHA错峰双跑不需要同步状态——两边各自向服务端收敛,一边刷完的章,另一边下轮探针自动跳过。2. 熔断与 cooldown——不会无限硬刷连续失败 ≥3 次 → 课程级BLOCKED;schedule触发下每累计 4 轮自动放行一次重试(cooldown 自动复位,可配),manual触发不受限、可立即干预;恢复成功计数清零。任务级还有「冻结」机制,反复失败的视频段不会堵死队列头部。3. 证据体系——每个 Run 可审计每章产出evidence/chapter_x.json:10 项闭合检查、business_verdict、passed_object_ids、failure_stage。失败分类到 10 种 stage(NO_CARDS_IFRAME/PLAYBACK_STALLED/LOGIN_FAILED…),CI 日志直接打印结构化诊断。出了问题看证据,不猜。4. 账号隔离与安全状态按state/accounts/CX_USER 哈希/隔离,cookie 存.cache/不入库;CI 上缺 Secrets 直接拒绝运行(exit 2),防止引擎跑到 fork 原作者的账本上。四、打包成 exe 的踩坑实录(本文最有干货的部分)依赖只有playwright1.63.0,理论上 PyInstaller 一把梭——实际踩了一路。坑 1:playwright 自带 hook 全量收集浏览器,spec 层过滤无效PyInstaller 没有 playwright 官方 hook,但playwright 包自己通过 entry point(pyinstaller40)注册了 hook,会把driver/package/.local-browsers/(含 271MB 的 headless shell)全部收进包。在 spec 的datas里过滤是无效的,必须在 Analysis 结果上过滤——而且.exe/.dll被归类为 BINARY 走a.binaries,两边都要滤:aAnalysis(...)a.datas[eforeina.datasifchromium_headless_shellnotine[0]]a.binaries[eforeina.binariesifchromium_headless_shellnotine[0]]这一刀从 835MB 砍到 564MB(所有启动点都是 headed,headless shell 纯死重;ffmpeg 保留,视频播放要用)。坑 2:contents_directory 写在 COLLECT 上会被静默忽略contents_directoryinternal必须写在EXE段(COLLECT 从 EXE 参数继承),写在 COLLECT 上不报错、静默回落_internal——产物能跑,布局和预期不一样,排查半天。坑 3:冻结后sys.executable -m app.run不成立调度器起子进程跑单章用的是sys.executable -m app.run;打包后sys.executable是 exe 自己,得改成 exe CLI 重入:ifgetattr(sys,frozen,False):cmd[sys.executable,--action,run,...]else:cmd[sys.executable,-m,app.run,...]坑 4:「修 A 引入 B」——停窗守卫把子进程挂死了双击 exe 报错后窗口闪退,我加了全局停窗守卫(input(按回车关闭窗口…))。结果下一轮真机测试,视频明明SERVER_CONFIRMED_PASS了,进程却在main()返回后卡在等回车,被看门狗 1562s 收割,PASS被聚合成FAILED,熔断计数 1。教训链:子进程重入 exe 也会走同一个守卫 → 守卫必须能被子进程跳过 → 调度器派生时注入XUE_NO_EXIT_PAUSE1,守卫检测即放行。顺带在聚合层加了防御:超时被杀、但子进程 evidence 里已是 PASS(服务端确认)→ 判成功,不污染熔断。坑 5:Path(__file__)在冻结态落到_MEIPASS全项目 10 处Path(__file__).resolve().parent.parent当仓库根,打包后全指进internal/(升级即丢)。收敛成单点:defrepo_root()-Path:# 可写根:state/ .cache/ evidence/ifgetattr(sys,frozen,False):returnPath(sys.executable).resolve().parentreturnPath(__file__).resolve().parent.parentdefresource_root()-Path:# 只读资源:_MEIPASS...源码形态返回值与旧表达式逐字节等价,GHA 路径零行为变化。坑 6:Windows 看门狗没有os.killpgkillpg是 POSIX 的;Windows 分支用taskkill /F /T /PID杀整棵进程树(不然超时只杀主进程,Chromium 泄漏一桌面)。坑 7:chromium 内置走PLAYWRIGHT_BROWSERS_PATH0构建前设PLAYWRIGHT_BROWSERS_PATH0跑playwright install chromium,浏览器落进 playwright 包内,随 PyInstaller 一起收进产物——自包含、离线可用;国内下载超时配PLAYWRIGHT_DOWNLOAD_HOSThttps://cdn.npmmirror.com/binaries/playwright或走代理。五、错峰双跑:本地和云端怎么共存同账号并发会互踢会话,所以两条腿时间窗错开(云端 cron 是北京 00:07/02:07)。状态收敛前面说了——靠服务端真源,不用 git 同步、不用网盘。要手动对账也行:state/accounts/哈希/整目录在 exe 旁和仓库之间拷贝即可,两边 schema 一致。六、数据与现状单测 集成504 passed;CI 三层工作流(test / e2 / e3)把守;产物dist/Xuexitong/564MB(内置 chromium),分发就是拷目录,升级只换Xuexitong.exeinternal/;宣传片是用 Remotion 写的(React 逐帧动画 Edge TTS 旁白),58 秒,纯代码渲染——工程在promo/,也算这套技术栈的顺手展示。完整操作手册(配置全表、错误速查 20 条、FAQ)在仓库docs/USER_MANUAL.md,打包后随 exe 附带。总结这个项目对我最大的价值不是「省了 20 小时」,而是把「不可靠的挂机」变成「可审计的流水线」:探针发现任务 → 真实播放 → 服务端确认 → 证据落盘 → 熔断兜底,每一环都有据可查。仓库:https://github.com/Thy985/xuexitong—— 觉得思路有用的话点个 Star;Issue / PR 都欢迎(尤其欢迎不同平台账号的实测反馈)。再次声明:请合理使用,遵守所在学校规定;工具只负责「真实地挂着」,学习本身没有捷径。
返回列表