皮皮舟岁月

A JOURNAL OF TRAVEL · CODE · MARKETS
第三十六期 · 第 36 号 二〇二六年八月 · 立秋之后

小鹅通视频抓取指南

2026-09-01 208 阅读

适用场景:抓取自己已购买/已授权的小鹅通直播回放、课程视频。核心思路是「通过网络面板抓取播放清单(m3u8)→ 批量下载分片 → 用 ffmpeg 拼接成完整 mp4」。文件抓下来后是无损的,画质音质与原片一致。


一、原理速览

小鹅通的直播回放/视频,典型工作方式:

  • 视频被切成很多个 10 秒分片.ts),由播放器逐个请求播放。
  • 一个文本清单文件 m3u8 记录了全部分片的字节区间时长,以及有无加密。
  • 分片地址形如:
    playlist.f3_0.ts?start=0&end=2165383&type=mpegts&sign=...&t=...&time=...&us=...&uuid=...
    
    其中 start/end 是该分片在整段流里的字节偏移sign/t/us/uuid/time鉴权参数(有时效,过期需重新抓)。

关键点:

  1. 只要拿到 m3u8 清单,就能拿到全部分片的下载地址。
  2. 如果清单里没有 EXT-X-KEY,说明未加密,可直接下载拼接。
  3. 如果时间太长签名的 t/time 过期,重新回网页刷新一次播放清单即可。

⚠️ 提醒:Network 里的请求带鉴权信息(可能含登录凭证),只用于你自己的设备,不要外发。


二、第一步:抓到 m3u8 清单(关键)

以下用 Chrome/Edge 操作:

  1. 登录小鹅通课程/回放页,进入视频播放页。
  2. F12 打开开发者工具,切到 Network(网络) 面板。
  3. 顶部过滤器框输入 m3u8
  4. 点击播放,或拖动进度条,让播放器重新拉取清单。
  5. 请求列表会出现一条以 .m3u8 结尾的记录(体积很小,几 KB),名字类似 playlist.f3.m3u8 / index.m3u8
  6. 右键该请求 → Copy → Copy as cURL,整段复制。

如果过滤 m3u8 没结果,就清空过滤器,找到名字里含 m3u8 的请求即可(注意别抓成大量 .ts 分片)。

抓到的 cURL 长这样:

curl --url 'https://encrypt-k-vod.xet.tech/522ff1e0vodcq1252524126/dc874c6a5001834817865932933/playlist.f3.m3u8?sign=2d65ea85...&t=6a98da93&us=...&time=...&uuid=...' \
  -H 'Referer: https://app4vz27eou7929.h5.xet.pomoho.com/' \
  -H 'User-Agent: Mozilla/5.0 ...'

三、第二步:下载 m3u8 到本地

把上面 cURL 里的地址(含 ?sign=...)保存成本地 playlist.m3u8 文件。

可以用 cURL 自己下载:

curl -s -o playlist.m3u8 \
  -H "Referer: https://app4vz27eou7929.h5.xet.pomoho.com/" \
  -H "User-Agent: Mozilla/5.0" \
  "https://encrypt-k-vod.xet.tech/.../playlist.f3.m3u8?sign=...&t=...&us=...&time=...&uuid=..."

查看清单,确认是否加密:

grep "EXT-X-KEY" playlist.m3u8   # 有输出 = 加密;无输出 = 未加密

四、第三步:批量下载全部分片

用 Python 解析 m3u8,生成下载清单并 16 路并行下载:

import os, urllib.parse

base = "https://encrypt-k-vod.xet.tech/522ff1e0vodcq1252524126/dc874c6a5001834817865932933/"
raw  = open("playlist.m3u8", encoding="utf-8").read()
segs = [l for l in raw.splitlines() if l and not l.startswith("#")]  # 每个分片URL

os.makedirs("segs", exist_ok=True)
with open("seg_cmds.txt", "w") as f:
    for i, s in enumerate(segs):
        u = urllib.parse.urljoin(base, s)
        f.write(f"segs/{i:04d}.ts\t{u}\n")
print("分片数量:", len(segs))
# 16 路并行下载(带上 Referer 和 UA)
awk -F'\t' '{print $1"\t"$2}' seg_cmds.txt | \
  xargs -P 16 -n 2 bash -c 'o="$0"; u="$1"; \
    curl -s -o "$o.fetch" -H "Referer: https://app4vz27eou7929.h5.xet.pomoho.com/" \
      -H "User-Agent: Mozilla/5.0" "$u" && mv "$o.fetch" "$o"'

# 校验:分片数量一致、没有空文件
ls segs/*.ts | wc -l
find segs -name "*.ts" -size -1000c | wc -l

五、第四步:拼接成完整 mp4(无损)

用 ffmpeg 的 concat 方式逐段拼接,不重新编码,速度快且无损:

python3 -c "
with open('segs_list.txt','w') as f:
    for i in range(853):  # 853 改成你的实际分片数
        f.write(f\"file 'segs/{i:04d}.ts'\n\")
"

ffmpeg -y -f concat -safe 0 -i segs_list.txt -c copy -movflags +faststart 输出.mp4

校验结果:

ffprobe -v error -show_entries format=duration,size \
  -show_entries stream=codec_name,codec_type,width,height \
  -of default=noprint_wrappers=1 输出.mp4

六、遇到问题怎么办

现象 原因 / 处理
下载分片返回 403 签名过期,t/time 是时效参数;回网页重新播放一次,重新抓 m3u8
m3u8 里有 EXT-X-KEY(加密) 需把 key 地址一并拿到;ffmpeg 有可能自动处理,否则需手动下载 key 后解密
找不到 m3u8 请求 先播放/拖动进度条刷新;清空过滤器找含 m3u8 的请求;勾选「保留日志」再刷新页面
视频很长、分片很多 耐心等下并行下载即可;16 路并行一条 2GB 视频通常几分钟内完成

七、可选:屏幕录制兜底方案

如果上面拿不到清单(例如 DRM/加密非常严),可用屏幕录制兜底:

  • macOS:黑盒虚拟声卡 + QuickTime/OBS 录屏录音。
  • 得到的是 .mov/.m4a,后续可用 ffmpeg 转格式/抽取音频:
    # 提取音频
    ffmpeg -i 录制.mov -vn -acodec copy 音频.m4a
    

按本指南抓取的视频请确保你有对应内容的观看/授权权限,仅限个人学习使用。

分享此文

评论 (0)

还没有评论,来抢沙发。

发表评论