Skip to content

Repository files navigation

三节课课程视频批量下载器

命令行工具,把在 三节课(sanjieke.cn) 已购买/已解锁的课程视频批量下载到本地做离线学习。

输入关键词或 course_id + 登录凭证,自动遍历课程目录树,逐节下载视频(HLS/M3U8,无 DRM)及字幕,按「课程/章节/小节.mp4」归档,支持断点续跑。

⚠️ 仅供个人已购课程的离线学习使用。请遵守平台服务条款,勿传播或用于商业用途。凭证与下载内容切勿外泄。


特性

  • 关键词搜索 + course_id 双入口:填关键词自动解析课程,或直接指定 course_id,两者合并去重。
  • 两步取流:目录树取 nodeId → 取详情拿短时效签名 m3u8 → 立即用 yt-dlp 下载合并。
  • 清晰度选择:自动挑可下载的最高清晰度;prefer_no_vip 控制是否规避 VIP 专属流(1080p)。
  • 字幕同步下载:中/英文 .vtt 落在视频同目录。
  • 会员免费课自动领取:未报名的会员免费课先调领取接口再取树。
  • 递归目录树:兼容扁平 / 两级 / 多级嵌套结构。
  • 断点续跑download_state.json 记录整门课完成情况,课内再按「文件是否已存在」跳过已下小节。
  • 容错不中断:单节失败记入失败清单继续;token 失效则安全停止本轮并提示更新凭证。
  • 分批下载batch_size 控制每轮课程数,降低风控风险。

环境依赖

  • Python 3.10+
  • 系统工具yt-dlp + ffmpeg(下载并合并 HLS 分片)
# macOS
brew install yt-dlp ffmpeg

# Python 依赖
pip install requests beautifulsoup4

快速开始

1. 配置凭证

复制模板并填入真实凭证(切勿提交 git.gitignore 已忽略 config.json):

cp config.example.json config.json

凭证从浏览器登录 sanjieke.cn 后抓取:

字段 来源
token 请求头 authorization: Bearer <JWT>,去掉 Bearer 前缀
apikey 请求头 sjk-apikey 的值
cookies._sjk_jwt / cookies.PHPSESSID 浏览器 Cookie

2. 填写要下载的课程

config.json 里二选一或都填(结果去重合并):

{
  "keywords": ["AI时代加速成长:从工具应用到效率飞跃"],
  "course_ids": ["34009802"]
}

3. 运行

python downloader.py

重复运行会自动跳过已下载的课程与小节。若设了 batch_size,每次跑一批,建议隔开时间再跑下一批。


配置项说明

config.json 全部字段(参见 config.example.json):

字段 说明 默认
keywords 关键词列表,逐个搜索解析成课程 []
course_ids 已知 course_id 直接下载,与 keywords 结果合并去重 []
token JWT,去掉 Bearer 前缀
apikey sjk-apikey
cookies _sjk_jwtPHPSESSID
user_agent 浏览器 UA
output_dir 输出根目录(可指向外置盘,如 /Volumes/Disk/Sanjieke downloads
prefer_no_vip true=只在非 VIP 流里选最高清;false=全部候选选最高(VIP 下 1080p) true
download_subtitles 是否下载字幕 true
request_delay_sec 接口调用间隔秒数(防风控) 1
batch_size 每轮下载课程数,0/缺省=一次全下 0

归档结构

output_dir/
  课程名/
    第一章 .../
      01_小节名.mp4
      01_小节名.ZH_CN.vtt
    ...
  另一门课/          # 扁平结构课程小节直接落在课程目录下
    01_小节名.mp4

文件名以零填充序号前缀保证播放顺序,非法字符替换为 _,超长名截断到 80 字。


核心链路(关键约束)

关键词 → GET sanjieke.cn/search?content=<kw>        (服务端渲染 HTML)
      → 解析 a.course-list-item 得详情页 url
      → GET 详情页,正则抠 window.__NUXT__.productData.course_id
      → GET content/tree/{course_id}                (course_id 即下载 id)
      → 逐节 content/{nodeId} 取 m3u8 → yt-dlp 下载 + 直连下字幕

改动代码前请务必先读 SPEC.md(权威文档),其中列出的约束违反后会跑飞:

  1. 两步取流:URL 路径用树的 nodeId,不是详情里的 contentId
  2. m3u8 是短时效签名链接:取详情后必须立即下载,不能先批量收集再统一下。
  3. 多种 id 易混淆:下载用 course_id(如 34009802)≠ m3u8 里的 class_id(如 37418645)。
  4. 清晰度vipFlag:true 的流非会员会 403,选流规则受 prefer_no_vip 控制。
  5. 一个 section 可能含多个视频节点,需遍历,多 node 时文件名加序号后缀防覆盖。
  6. 会员免费课未报名需先 POST /cms-agg/api/vip/free_course 领取再取树。

相关文件

文件 说明
downloader.py 主程序(单文件实现)
SPEC.md 完整需求与接口契约(权威文档)
precheck.py 下载前预检脚本
PROGRESS.md 下载进度与运维经验记录
config.example.json 配置模板

容错与运维提示

  • token 失效:401 时立即停止整轮(TokenRevoked),重新登录抓新凭证更新 config.json 后再跑,已完成的会跳过。
  • 多客户端登录会封号:下载期间勿在别处登录同一账号。
  • 单个视频失败(网络/token)不中断整体,末尾汇总失败清单。
  • 搜索无结果或无精确匹配时打印候选,不静默瞎选。

License

MIT © libingtong

About

三节课(sanjieke.cn)已购课程视频批量下载器:关键词/course_id 搜索、HLS 取流、字幕下载、断点续跑

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages