学在西电录播课使用python下载,通过解析m3u8协议、多线程下载ts视频块以及ffmpeg合并
本文涵盖的内容仅供个人学习使用,如果侵犯学校权利,麻烦联系我删除。
初衷
研究生必修选逃, 期末复习怕漏过重点题目,但是看学在西电的录播回放课一卡一卡的,于是想在空余时间一个个下载下来,然后到时候就突击复习。
环境
因为懒得用二进制安装ffmpeg,所以用的Ubuntu22.04。年轻的本科生windows选手们可以自行学习二进制安装ffmpeg。
sudo apt install ffmpeg
ffmpeg -version
# 要有python3,安装步骤略过
...
# pip依赖
pip install aiohttp
pip install tqdm
pip install m3u8
预备知识
关于网站部分,本文写于2024-12-05,不保证后面会不会改
学在西电就是在学习通上再加了一层,加了点新东西。录播在这个地方看。(本文默认已经登录成功)
下面的图就是录播播放界面,由于有学生姓名和学号的水印,我打码了。
左边是拍老师和黑板的录像,右边是展示ppt的录像。
为了捕获请求,我们先打开开发者面板的网络面板,点击下面的某堂课跳转,然后在页面刷新后获取到加载时的请求,通过关键词过滤m3u8
,得到重要的三个请求。
注意这里有两个playback.m3u8
,通过上面图中那个另外的请求playVideo?info=...
的响应,我们可以看到pptVideo
和teacherTrack
这两个路径,分别对应ppt和老师黑板的m3u8文件的url。
{"type": "2","videoPath": {"pptVideo": "....m3u8","teacherTrack": "....m3u8","studentFull": "....m3u8"},"liveId": ...,"isshowpl": 0
}
在学在西电里,视频文件是被切分为许多个几秒的视频块(ts文件,是Transport Stream不是Typescript),通过一个m3u8协议文件保存对应视频的各个小视频块的文件名、序列号、持续时间等信息。
m3u8文件内容如下,还好学在西电这里没有做加密,没有#EXT-X-KEY:METHOD=AES-128,URI...
这么一行,所以我们可以用这些ts文件名直接下载(当然前面还要有http之类的前缀)。
最后,使用伟大牛逼的 ffmpeg 可以将这些ts文件合并为 mp4 文件。
具体代码
1. 下载各ts
基于m3u8
库解析m3u8文件,aiohttp
做协程下载,tqdm
做进度条方便查看,最后记得threading加锁。
考虑到偶尔的下载异常,加了个3次重试。
url按照下图获取。
实测5分钟左右下完。
# download.py
import shutil
import threading
import m3u8
import os
import logging
import re
import asyncio
import aiohttp
from tqdm import tqdmpbar:tqdm = None
pbar_lock = threading.Lock()async def download_segment(session, ts_url, true_url, output_dir, cnt):global pbarfilename = os.path.join(output_dir, true_url)try:# 实际在这里下载async with session.get(ts_url) as resp:resp.raise_for_status()with open(filename, 'wb') as f:async for chunk in resp.content.iter_chunked(1024):if chunk:f.write(chunk)logging.info(f"下载完成: {true_url}")with pbar_lock:pbar.update(1)except Exception as e:logging.error(f"下载失败: {true_url}, 错误信息: {e}")# 3次重试机会if cnt == 3:logging.error(f"重试次数达到上限,跳过下载: {true_url}")# 把需要手动下的单独保存with open(f'{output_dir}.err', 'a', encoding='utf-8') as file:file.write(ts_url + '\n')# 并且这个下了一半的ts文件需要删掉,防止弄混if os.path.exists(filename):os.remove(filename)with pbar_lock:pbar.update(1)else:# 重试一下,且计数器+1await download_segment(session, ts_url, true_url, output_dir, cnt+1)async def download_m3u8(m3u8_url, output_dir):global pbar# 日志logging_file = f'{output_dir}-download.log'err_file = f'{output_dir}.err'if os.path.exists(logging_file):os.remove(logging_file)if os.path.exists(err_file):os.remove(err_file)if os.path.exists(output_dir):shutil.rmtree(output_dir)logging.basicConfig(filename=logging_file, level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')# 创建输出目录os.mkdir(output_dir)# 下载并解析 m3u8 文件logging.info(f"开始解析 m3u8 文件: {m3u8_url}")m3u8_obj = m3u8.load(m3u8_url)# 提取 base URLbase_url = re.split(r"[a-zA-Z0-9-_\.]+\.m3u8", m3u8_url)[0]logging.info(f"提取到的base URL: {base_url}")# 创建 aiohttp sessionasync with aiohttp.ClientSession() as session:# 异步下载所有 ts 片段tasks = []pbar = tqdm(total=len(m3u8_obj.segments))logging.info(f"segment 个数: {len(m3u8_obj.segments)}")for _, segment in enumerate(m3u8_obj.segments):# 真正ts的下载url是要拼起来的ts_url = base_url + segment.uritask = asyncio.create_task(download_segment(session, ts_url, segment.uri, output_dir, 0))tasks.append(task)await asyncio.gather(*tasks)# 任务完成后关闭进度条pbar.close()logging.info(f"下载完成")m3u8_url = "http://.../playback.m3u8"
output_dir = "2-4-1-1"
asyncio.run(download_m3u8(m3u8_url, output_dir))
2. 合并为mp4
基于命令: ffmpeg -f concat -safe 0 -i ts_list.txt -c copy video.mp4
。注意这个-i
,如果只有少量文件,可以-i "concat:1.ts|2.ts|3.ts|4.ts|.5.ts|"
,但对于我们这种,就只能让他读取一个文件名列表文件,注意这个文件每行都是file+文件路径
。
我代码里首先获取了ts文件夹里的所有ts文件名,但是因为多线程所以乱序,要先排个序才能让ffmpeg按顺序拼接。
实测1分钟左右合并完成。
# merge.py
import osdef main(dir_name):filename = 'ts_list.txt'if os.path.exists(filename):os.remove(filename)f = open(filename, 'a', encoding='utf-8')names = []with os.scandir(dir_name) as entries:for entry in entries:# 检查是否为文件if entry.is_file():names.append(entry.name)# 注意要先排序,按顺序写入文件名names.sort(key=lambda x: int(x.split('_')[0]))for name in names:f.write(f"file {os.path.join(dir_name,name)}\n")f.close()mp4_name = f"{dir_name}.mp4"if os.path.exists(mp4_name):os.remove(mp4_name)cmd = rf'ffmpeg -f concat -safe 0 -i ./{filename} -c copy {mp4_name}'os.system(cmd)main("./4-2-1-ppt")
3. 执行
运行前记得改两个脚本里的链接和文件名
python download.py
python merge.py
其他
- 其实也可以直接用ffmpeg一次完成:
ffmpeg -i http://.../playback.m3u8 -c copy 2-4-1.mp4
,只是似乎是串行依次下载ts,速度不快。 - 我也有搜到用IDM下载或者potplayer播放,学长/弟/姐/妹可以自行尝试。
- 学在西电课程回放稳定播放方法
- 手把手教你用IDM下载学在西电课程回放视频
- 关于ppt视频的忽略音频流,ffmpeg可以设置参数,我没看这个
- 关于字幕生成,免费方案是B站必剪支持15分钟内视频的字幕生成,可以在必剪里裁剪和生成,但是有点麻烦而且效果很差。其他方案请自行研究。
- 似乎也有直接可用的m3u8播放器,请自行研究。
相关文章:

学在西电录播课使用python下载,通过解析m3u8协议、多线程下载ts视频块以及ffmpeg合并
本文涵盖的内容仅供个人学习使用,如果侵犯学校权利,麻烦联系我删除。 初衷 研究生必修选逃, 期末复习怕漏过重点题目,但是看学在西电的录播回放课一卡一卡的,于是想在空余时间一个个下载下来,然后到时候就…...

Springboot3介绍
一、Springboot3简介: https://docs.spring.io/spring-boot/docs/current/reference/html/getting-started.html?spmwolai.workspace.0.0.68b62306Q6jtTw#getting-started.introducing-spring-boot 无论使用XML、注解、Java配置类还是他们的混合用法,配置文件过于…...
Oracle 11G DataGuard GAP 修复过程(通过主库scn增备恢复)
Oracle 11G DataGuard GAP 修复 (通过主库scn增备恢复) 介绍 DG GAP 顾名思义就是:DG不同步,当备库不能接受到一个或多个主库的归档日志文件时候,就发生了 GAP。 那么,如果遇到GAP如何修复呢?…...

WLAN AutoConfig服务假死?重启服务恢复网络连接!
目录 背景: 过程: 可能引起原因: 具体解决步骤: 方法一: 方法二: 总结: 背景: 这个问题困扰我好长一段时间了,每次下班将电脑关机后,次日早上电脑开机…...
【linux】(30)shell-条件判断
if 语句 if 语句是 Shell 脚本中用于条件判断的基本结构。 基本语法 if 语句的基本语法如下: if [ condition ] thencommands ficondition 是要测试的条件。commands 是在条件为真时要执行的命令。 示例 简单条件判断 #!/bin/bashif [ 1 -eq 1 ] thenecho &q…...

docker安装启动问题解决排查
一、安装docker报错 刚开始安装docker报这个错: Error: Transaction test error: file /usr/libexec/docker/cli-plugins/docker-buildx from install of docker-ce-cli-1:20.10.8-3.el8.x86_64 conflicts with file from package docker-buildx-plugin-0:0.14.0…...
《MySQL 查询进阶:复杂查询语句的魅力》
一、引言 MySQL 的复杂查询语句就像是一把神奇的钥匙,能够打开数据世界的大门,展现出数据的无限魅力。本文将带你深入探索 MySQL 查询进阶技巧,从常用查询到子查询,再到视图的运用,让你领略复杂查询语句的强大功能。 …...

OpenHarmony-3.HDF框架(2)
OpenHarmony HDF 平台驱动 1.平台驱动概述 系统平台驱动框架是系统驱动框架的重要组成部分,它基于HDF驱动框架、操作系统适配层(OSAL, operating system abstraction layer)以及驱动配置管理机制,为各类平台设备驱动的实现提供标准模型。 系统平台驱动(…...

人大金仓(KingBaseEs)数据库操作手册
人大金仓数据库(KingbaseES)是由北京人大金仓信息技术股份有限公司(简称人大金仓)自主研发的、具有自主知识产权的通用关系型数据库管理系统。 官方下载地址:KingbaseES 人大金仓数据库 KES技术文档在线手册…...

Flink+Paimon实时数据湖仓实践分享
随着 Paimon 近两年的推广普及,使用 FlinkPaimon 构建数据湖仓的实践也越来越多。在 Flink 实时数据开发中,对于依赖大量状态 state 的场景,如长周期的累加指标计算、回撤长历史数据并更新等,使用实时数仓作为中间存储来代替 Flin…...

w~深度学习~合集1
我自己的原文哦~ https://blog.51cto.com/whaosoft/12663254 #Motion Plan 代码 github.com/liangwq/robot_motion_planing 轨迹约束中的软硬约束 前面的几篇文章已经介绍了,轨迹约束的本质就是在做带约束的轨迹拟合。输入就是waypoint点list,约束…...

KVM 虚拟化
KVM(Kernel-based Virtual Machine)是一种基于内核的虚拟机技术,具有以下优势: 开源性:KVM是完全开源的,这意味着它没有许可费用,适合预算有限的用户。性能:KVM利用Linux内…...
MONI后台管理系统-数据库设计
前言:该文档纯属个人总结设计,如果雷同,纯属巧合,其中还有很不合理之处,请大家批评指正。如有应用于项目,请慎重。 注意: 如有需要该文件的sql脚本,请移步:资源下载 1. 表清单 序号…...

Rigol DP711自动控制--SCPI命令
通过串口的SCPI命令来控制通道输入输出 也可以用UltraSigma UI来发送SCPI 物理连接: Pin2_2, Pin3_3, Pin5_5 串口命令控制: 命令:9600, 8bit, None SCPI CMD(Standard Commands for Programmable Instruments) OUTPut CH1, On…...

总结FastDFS的面试题
目录 一:FastDFS的基础知识 1:定义 2:FastDFS的优点 3:tracker server 4:storage server 二:FastDFS的存储原理 1:小文件存储的问题 2:小文件合并存储 3:文件上…...

Fiddler 5.21.0 使用指南:过滤浏览器HTTP(S)流量下(四)
概述 在上一篇文章中,我们介绍了一部分简单的过滤功能,已经可以帮助我们较为准确的定位到感兴趣的请求;提升我们的工作效率,我们可以通过设置更为复杂的过滤规则,精准到定位的我们想要的请求和响应信息。专注于分析对…...

【踩坑】pip安装依赖卡在Installing build dependencies ...
pip安装依赖卡在Installing build dependencies ... 如图,pip安装依赖一直卡着,最后不得不ctrlC强制终止 用–verbose显示详细安装信息,发现卡在安装numpy pip install -r requirements.txt --verbose大概率是网络问题,用镜像单…...
【WRF-Urban】SLUCM新增空间分布城市冠层参数及人为热排放AHF代码详解(下)
目录 详细解释更改文件内容4 运行模块(run):README.namelist5 输出模块(share):share/module_check_a_mundo.Fshare/output_wrf.F参考SLUCM新增空间分布城市冠层参数及人为热排放AHF代码详解的前两部分内容可参见-【WRF-Urban】SLUCM新增空间分布城市冠层参数及人为热排放A…...
云桌面:云计算桌面
目录 云桌面的定义和核心概念 技术架构详解 主流架构详解 管理成本分析 安全性措施 应用场景详解 云桌面的定义和核心概念 云桌面是一种通过云计算技术提供的虚拟桌面服务,它允许用户通过网络访问远程服务器上的虚拟机,这些虚拟机为用户提供了一个…...

WPF+LibVLC开发播放器-音量控制和倍速控制
界面 界面上增加音量的控件和倍速控制控件 音量控制 主要也是一个Slider进度条控件来实现音量调节 我们这里设置默认的最大值为100,默认Value值也为100,默认声音开到最大 这里目前完全由前端控制音量调节,可以直接使用ValueChanged事件实…...

docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...

UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...

Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...

Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...

无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...