把某在线教育平台的 345 门培优课程(视频 + 学案)批量下载并归档到 OSS,中途经历用户需求变更(停三科)、大视频断连、脚本崩溃、跨桶迁移四轮考验。配套 skill:
oss-data-management(devops)与chinese-edtech-spa-scraping(research)。
一、项目背景
- 目标:345 门培优课程(视频 mp4 + 学案 docx),按学科归档到 OSS
- 学科分布:数学 117 / 化学 61 / 语文 56 / 英语 46 / 物理 34 / 生物 31
- 环境约束:40G 磁盘、1.8G 内存,下载要流式(下→传→删)
二、逆向与探测
2.1 接口分析
配套 skill chinese-edtech-spa-scraping 固化了一套国内教育平台 SPA 逆向方法:
- 抓包分析 API:课程列表 / 播放地址 / 学案下载
- 多轮探测脚本(course_recon / course_api_list / course_fetch_all)
- 鉴权方式确认:无登录态下大部分接口可访问(学案 docx 直接可下)
2.2 清单构建
全量课程清单 course_final_manifest.json:345 门,按学科分组,每门含 videos(url+name)+ docs(url+name)。
三、批量下载器设计
3.1 核心架构:流式下载
1 | 逐门课程: 下载全部文件 → 上传 OSS → 删除本地 |
- 磁盘保护:本地占用超阈值先上传清理(DISK_SAFE_GB=3.0)
- 断点续传:done_files 标记 + 远端存在性校验,重跑只补失败
- 温柔对待服务器:每门课之间 sleep 1.5s
3.2 关键参数
- 单文件超时 1 小时(DOWNLOAD_TIMEOUT),curl 重试 3 次
- 进度 JSON 实时落盘(course_download_progress.json,可中断恢复)
- 已标记的跳过逻辑:本地在则跳过;本地不在则确认远端存在;远端也没有才重新下载
四、三大工程问题
4.1 大视频反复失败
2.1GB 的基因定位视频反复断连。curl 无断点续传导致每次从头下。
解法:专项脚本 course_resume.py 用 curl -C - 断点续传 + 5 次重试:
1 | cmd = ['curl', '-skL', '-C', '-', '--retry', '3', '--retry-delay', '3', |
实测:从 517MB 断点续传到 2.1GB 成功(curl=18 服务器断连后自动续传)。
4.2 脚本崩溃(FileNotFoundError)
download_file 中 curl 失败删残文件后未 return,继续执行 os.path.getsize 崩溃:
1 | FileNotFoundError: [Errno 2] ... 反证法.mp4 |
解法:补存在性检查,失败立即返回 False(这是基础 bug,但直到真实跑批才暴露)。
4.3 用户中途变更需求
「语文、英语、化学的课程不要继续下载了,下了的打包成压缩包」——脚本加 SKIP_SUBJECTS 集合:
1 | SKIP_SUBJECTS = {"语文", "英语", "化学"} |
重启进程自动跳过 163 门。已下内容保留,未下三科不再下。
五、补跑机制
5.1 失败课程重跑
错误按课程记录(errors dict),补跑只移除失败课程的 done_courses 标记,保留 done_files(已完成文件跳过):
1 | retry_ids = {cid for cid in errors if cid_subj.get(cid) not in SKIP_SUBJECTS} |
5.2 最终结果
- 数学 117/117、物理 34/34、生物 31/31 全量完成
- 语文 41/56、英语 34/46、化学 27/61(按用户要求停止)
- 706 文件上传 OSS 备份桶
- 剩余 18 门错误全部是停科目(按用户要求不再下载)
六、OSS 跨桶迁移
6.1 需求
「把下载好的全部转移到归档桶里面,我现在给了你两个桶的权限(在归档桶账号里面),直接同区域复制即可」
6.2 两轮方案
- 下载→上传中转(初始,无跨桶权限时):30GB 走本地网络中转,约 60 对象/分钟
- 服务端复制(拿到权限后):
copy_object同区域秒级复制,不占本地带宽——17 分钟复制 86.6GB
6.3 服务端复制实现
1 | DST = oss2.Bucket(oss2.Auth(DST_AK, DST_SK), 'http://oss-cn-<region>-internal.aliyuncs.com', 'archive-bucket') |
关键细节:
- 同区域内网 endpoint 直连(
oss-cn-<region>-internal) - 幂等:目标已存在且大小一致自动跳过,重跑安全
- 源桶用 default 凭据,目标桶用子账号凭据
6.4 对账验证
逐学科核对源/目标对象数与字节数:
1 | 语文 103 ✅ 数学 290 ✅ 英语 77 ✅ |
首次发现数学缺 4、生物缺 2(复制期间新文件刚上传的时序差),幂等重跑补齐(复制 5 + 复制 2),失败 0。
七、配套 skill:oss-data-management
- OSS 桶管理:个人资料桶 / 备份桶 / 量化数据桶 / 归档桶(多桶统一管理)
- 凭证规范:~/.hermes/.env(systemd 注入)或 ~/.oss_credentials(ini,cli 工具用)
- 数据路径映射表:量化数据本地 ↔ OSS 的对应关系
- 上传下载 / 访问追踪 / 冷数据归档
关键教训(skill 内记录):OSS 凭据节名要查脚本确认(误用业务桶名当凭据节名得 0 对象,改 ‘default’ 才通)。
八、工程经验
- 断点续传是数据工程的命门:大文件传输必须
-C -,否则永远在下最大的那个 - 幂等是重跑的底气:大小校验 + 标记跳过,随便重跑不重复
- 服务端复制优先:同区域 copy_object 秒级且零带宽,别傻下载
- 对账不能省:对象数 + 字节数双指标,缺一不可
- 需求变更要留接口:SKIP_SUBJECTS 集合让「停三科」一行配置生效
- 日志要防二进制污染:下载 mp4 时 stdout 被内容污染(\u0000 垃圾),日志重定向 + grep 过滤
- 基础 bug 也会爆:getsize 前没查 exists——真实跑批才能暴露