title: Advanced SCU Course Catcher
emoji: 🐳
colorFrom: green
colorTo: yellow
sdk: docker
app_port: 7860
pinned: false
Advanced SCU Course Catcher
这是一个面向 Hugging Face Space 的四川大学选课系统 Web 版抢课面板。当前版本已经从单机脚本改造成了可部署、可并行、可多用户管理的 Flask + Selenium 服务,支持普通用户端和管理员端分离运行。
当前能力
- 普通用户入口:
/login用户使用学号 + 密码登录,只能看到自己的课程、任务状态和实时日志。 - 管理员入口:
/admin管理员使用账号 + 密码登录。此入口不会在用户登录页展示。 - 多管理员体系
支持多位普通管理员,支持 1 位超级管理员。超级管理员账号和密码由环境变量
ADMIN、PASSWORD提供。 - 多用户管理 管理员可以手动录入用户账号、重置密码、启用/禁用用户、查看所有课程目标。
- 课程录入
用户自己填写
课程号和课序号,管理员可见全部内容,也可以代为录入和修改。 - 实时日志 用户和管理员都可以实时看到程序日志,前端通过 SSE 持续推送。
- 并行调度 多用户任务由后台任务调度器并行执行,管理员可以在后台动态设置并行数。
- Hugging Face Space 适配 使用 Docker Space 运行,内置 Chromium、chromedriver、中文字体和无头浏览器配置。
- 登录验证码与提交验证码 OCR 登录阶段和提交选课阶段都支持验证码 OCR 自动识别。
- Selenium 自恢复 单个 Selenium 会话连续错误达到 5 次时,会自动重建浏览器;连续重建 5 个会话仍失败时,任务才会终止。
运行结构
当前实际运行入口和核心模块如下:
app.pyHugging Face / gunicorn 使用的 WSGI 入口。space_app.pyFlask 路由、页面渲染、登录鉴权、SSE 日志流。core/config.py运行配置与内部密钥管理。core/db.pySQLite 数据层。core/task_manager.py并行调度、任务生命周期管理。core/course_bot.pySelenium 抢课核心逻辑、验证码识别、重试与重建策略。webdriver_utils.pyChromium / chromedriver 初始化。templates/+static/用户端、管理员端和响应式前端页面。
环境变量
为了减少 Space 配置复杂度,当前只保留少量必要环境变量。
必填
ADMIN超级管理员账号。PASSWORD超级管理员密码。
可选
DATA_DIR数据目录,默认会使用仓库下的data/。在 Hugging Face Space 中建议保持为/data。CHROME_BIN自定义 Chromium 路径。默认会自动尝试/usr/bin/chromium。CHROMEDRIVER_PATH自定义 chromedriver 路径。默认会自动尝试/usr/bin/chromedriver。
不需要再手动配置的内容
以下内容已经改为自动生成或写入程序默认值,不需要再手工配置环境变量:
- Flask session secret
- 用户密码加密密钥
- 默认并行数
- 登录重试次数
- Selenium 会话错误阈值
- Selenium 会话重建阈值
- 提交验证码重试次数
- 页面超时时间
- 日志页容量
程序会在 DATA_DIR/.app_secrets.json 中自动持久化内部密钥。这样即使以后修改 ADMIN 或 PASSWORD,也不会导致历史用户密码全部失效。
Hugging Face Space 部署
1. 创建 Space
在 Hugging Face 上创建一个新的 Space:
- SDK 选择
Docker - 端口使用
7860 - 仓库内容直接推送本项目即可
本仓库根目录已经提供好 README.md 的 Space metadata 和 Dockerfile。
2. 设置 Space Secrets
进入 Settings -> Variables and secrets,至少配置:
ADMIN=你的超级管理员账号PASSWORD=你的超级管理员密码
通常不需要再设置其他环境变量。
如果你想显式指定数据目录,也可以增加:
DATA_DIR=/data
3. 开启持久化存储
如果你希望以下数据在 Space 重启后仍然保留,建议在 Space 设置里开启 Persistent Storage:
- 用户账号
- 管理员账号
- 课程目标
- 任务历史
- 运行日志
- 自动生成的内部密钥文件
当前 Dockerfile 已按 /data 目录进行适配,并预先处理了目录权限,方便在 Space 中直接持久化。
4. 推送部署
如果你使用 git 推送到 Hugging Face Space,可以参考:
git remote add space https://huggingface.co/spaces/<your-name>/<your-space>
git push space main
5. 启动方式
容器启动命令已经写入 Dockerfile:
gunicorn --bind 0.0.0.0:${PORT:-7860} --workers 1 --threads 8 --timeout 180 app:app
这里使用 1 个 gunicorn worker,是为了避免多进程情况下每个进程都各自启动一套本地任务调度器。并发能力由应用内部的线程调度和管理员可配置的任务并行数控制。
Space 端建议配置
推荐的初始运行策略:
- 后台并行数先设置为
1或2 - 只有在 Space CPU / 内存足够稳定时,再逐步提升
- 在真实高峰前,先做一次小规模联调
对于 CPU 较小的 Space,同时拉起过多 Chromium 会明显增加失败率,因此管理员后台提供了并行数动态调整功能。
管理员联调清单
部署到 Space 后,建议按以下顺序联调:
- 访问
/admin,使用ADMIN/PASSWORD登录超级管理员。 - 在管理员后台创建 1 个普通管理员、2 个测试用户。
- 为两个测试用户分别录入不同课程号和课序号。
- 将并行数设置为
2。 - 分别触发两个用户任务,确认两条任务都能进入队列,并按并行数启动。
- 在管理员日志面板确认日志持续刷新,且可以看到不同学号的执行记录。
- 使用用户账号访问
/login,确认用户只能看到自己的课程和日志。 - 在任务运行过程中测试停止任务,确认状态能变为“停止中”并最终收敛。
- 如果学校页面出现提交验证码,确认日志中能看到提交阶段验证码识别提示。
自动化测试
仓库当前已补充以下自动化测试:
tests/test_config.py验证内部密钥在超级管理员账号变更后依然保持稳定。tests/test_course_bot.py验证 Selenium 会话错误累计后会触发浏览器重建,并验证提交阶段验证码分支。tests/test_task_manager.py验证任务调度器会严格遵守管理员设置的并行上限。.github/workflows/linux-tests.yml在ubuntu-latest上自动运行上述测试,避免关键逻辑只在 Windows 本地验证。
本地运行测试:
python -m unittest discover -s tests -v
本地运行
直接运行
pip install -r requirements.txt
set ADMIN=admin
set PASSWORD=change-me
python main.py
Docker 运行
docker build -t advanced-scu-course-catcher .
docker run --rm -p 7860:7860 \
-e ADMIN=admin \
-e PASSWORD=change-me \
advanced-scu-course-catcher
重要说明
- 本项目当前的任务模型是“持续轮询直到成功、手动停止或达到错误上限”。
- 用户密码会以应用内部密钥加密后保存在数据库中,用于后台自动登录教务系统。
- 管理员可以看到全部用户、课程和日志,请在实际使用前明确权限边界。
- 如果学校选课页面 DOM 结构变化较大,需要同步更新
core/course_bot.py中的选择器以及javascript/下的辅助脚本。 course_catcher/目录是仓库中保留的旧实现,当前运行链路以space_app.py + core/*为准。