文章目录
- 一、背景
- 二、HLS协议
- 三、M3U8文件
- 四、TS视屏流封装格式
-
- 4.1 TS层
- 4.2 PES层
- 4.3 ES层
- 五、m3u8和mp4转换
-
- 5.1 mp4转m3u8
- 5.2 m3u8转mp4
- 六、HLS vs RTSP
-
- 6.1 RTSP(Real Time Streaming Protocol)
- 6.2 HLS 和 RTSP对比
-
- 应用场景
- 发展趋势
- 七、电视迷视频下载实战
-
- 7.1 网页分析
- 7.2 爬虫方案
- 7.3 解析index.m3u8
- 7.4 解析mixed.m3u8
- 7.5 去菠菜广告视频
- 八、参考链接
一、背景
当前很多视频网站使用m3u8文件进行视频播放,m3u8文件时hls(http live stream)协议的一部分,传统的rtsp协议对于http视频播放场景网络不佳的场景没法做到动态自适应分辨率,而且当前浏览器没有天然支持rtsp协议,所以苹果公司推出hls协议,使用播放列表m3u8文件和ts文件实现http的视频播放技术。本文详细介绍一下hls协议,对比一下hls和rtsp的差异,并且以电视迷网站视频下载做m3u8视频文件下载的实战介绍。
二、HLS协议
HLS HTTP Live Streaming 是苹果公司提出的基于 HTTP 的流媒体协议,基本实现原理为将一个大的媒体文件进行分片,将该分片文件资源路径记录于 m3u8 文件(即 playlist)内,其中附带一些额外描述(比如该资源的多带宽信息···)用于提供给客户端。客户端依据该 m3u8 文件即可获取对应的视频流ts媒体资源,进行播放。
hls = m3u8文件 + ts视频流
工作原理:
- 切片(Segmentation): 视频源(如直播流或点播文件)被编码器实时地切割成一系列小的、连续的 TS 格式视频文件片段(例如每个片段时长2-10秒)。
- 创建索引(Playlist): 同时,编码器会生成一个不断更新的索引文件(M3U8 格式的播放列表)。这个文件记录了所有 TS 片段的URL和元数据(如码率、分辨率)。
- 分发(Distribution): 这些 TS 片段和 M3U8 文件通过标准的 HTTP 服务器分发,就像分发普通的网页图片一样。
- 播放(Playback): 播放器(如浏览器中的 video.js 或移动端播放器)首先下载 M3U8 文件,然后按顺序下载 TS 片段,并逐个播放,实现无缝的视频观看体验。
优点:
- 高兼容性/穿透性: 使用 HTTP 协议,可以轻松通过任何防火墙或代理服务器,因为互联网就是为 HTTP 优化的。
- 强大的自适应能力: HLS 的核心特性。编码器可以生成同一视频内容、不同码率(如 1080p、720p、480p)的多套 TS 片段和对应的 M3U8 文件。播放器可以根据当前网络状况自动选择最合适的码流进行下载,保证流畅播放。
- 高可靠性: 基于 TCP 的 HTTP 协议确保了数据传输的可靠性,即使网络有波动,也只会导致下载变慢,而不是数据丢失。
- 易于缓存和CDN加速: 视频片段是静态的 HTTP 资源,可以被广泛分布的 CDN 节点缓存,极大减轻源站压力。
缺点:
- 高延迟: 这是 HLS 最大的缺点。延迟来源于"切片时间 + 缓冲区时间"。为了确保流畅性,播放器通常会预先下载好几个片段,导致延迟远大于单个片段的时长,通常在 10 秒以上。虽然通过低延迟 HLS 技术可以优化到 3 秒左右,但依然不如 RTSP。
三、M3U8文件
HLS协议中,使用m3u8文件来保存播放列表,m3u8文件是extend M3U (MP3 URL) files文件,其中8表示使用utf8编码,m3u文件最初是用于传输mp3文件列表信息,扩展后可以用来传输视频信息。m3u8文件内容格式如下,其中保存了具体视频ts的url,浏览器下载m3u8文件后根据url下载对应的ts文件进行播放。
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-TARGETDURATION:8
#EXT-X-DISCONTINUITY
#EXTINF:4.000000,
b9754d299d5000000.ts
#EXTINF:4.080000,
b9754d299d5000001.ts
#EXTINF:3.960000,
b9754d299d5000002.ts
#EXT-X-ENDLIST
EXTM3U: 表示这是一个m3u8文件,必须在文件的第一行,所有的M3U8文件中必须包含这个标签。
EXT-X-ENDLIST:切片序列结束的标记。
XT-X-VERSION:文件版本,常见是3
EXT-X-PLAYLIST-TYPE:播放列表类型,常见是VOD。
EXT-X-MEDIA-SEQUENCE:播放的序列号。
EXT-X-TARGETDURATION:该标签指定了媒体文件持续时间的最大值,播放文件列表中的媒体文件在EXTINF标签中定义的持续时间必须小于或者等于该标签指定的持续时间。该标签在播放列表文件中必须出现一次。
EXT-X-DISCONTINUITY:通知播放器解码时清除缓存,画面与前面可能存在较大差异,编码、分别率可能变化等,比如在视频中插入广告。
EXTINF: 里面保存的视频序列,格式如下:先是说明视频的长度,然后使用逗号分隔,后面跟ts文件的链接。
#EXTINF:4.000000,
b9754d299d5000000.ts
上述ts链接是本地文件名,使用网络传输时需要使用浏览器js脚本下ts播放,另外一种方式是m3u8文件中固定好ts的网络url,如下方式,但是这种对于生成m3u8文件就会复杂一些,并且不利于cdn解析。
#EXTINF:4.000000,
http://test.com/b9754d299d5000000.ts
客户端播放M3U8的文件的一些注意事项:
- 分片必须是动态改变的,序列不能相同,并且序列必须是增序的。
- 当M3U8没有出现EXT-X-ENDLIST标签时,无论这个M3U8列表中有多少分片,播放分片都是从倒数第三片开始播放,如果不满三片则不应该播放。当然如果有些播放器做了特别定制了,则可以不遵照这个原则。
- 以播放当前分片的duration时间刷新M3U8列表,然后做对应的加载动作。
- 前一片分片和后一片分片有不连续的时候,播放可能会出错,那么需要X-DISCONTINUTY标签来解决这个错误。
- 如果播放列表在刷新之后与之前的列表相同,那么在播放当前分片duration一半的时间内在刷新一次。
- 扩展的m3u8属性EXT-X-STREAM-INF
EXT-X-STREAM-INF标签出现在M3U8时,主要是出现在多级M3U8文件中时,例如M3U8中包含子M3U8列表,或者主M3U8中包含多码率M3U8时;该标签后需要跟一些属性,下面就来逐一说明一下这些属性:
- BANDWIDTH:BANDWIDTH的值为最高码率值,当播放EXT-X-STREAM-INF下对应的M3U8时占用的最大码率(必要参数)。
- AVERAGE-BANDWIDTH:AVERAGE-BANDWIDTH的值为平均码率值,当播放EXT-X-STREAM-INF下对应的M3U8时占用的平均码率。(可选参数)。
- CODECS:CODECS的值用于声明EXT-X-STREAM-INF下面对应M3U8里面的音视频编码、视频编码的信息(可选参数)。
- RESOLUTION:M3U8中视频的宽高信息描述(可选参数)。
- FRAME-RATE:子M3U8中的视频帧率(可选参数)。
比如:如下index.m3u8中包含一个实际的mixed.m3u8文件路径。
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=800000,RESOLUTION=1080x608
2000k/hls/mixed.m3u8
四、TS视屏流封装格式
TS是mpeg-ts格式视频流封装格式,而非压缩格式,每个ts片段可以独立解码。对应ITU规范是H.222 H.222.0 : Information technology - Generic coding of moving pictures and associated audio information: Systems。ts配合m3u8中可以保存多份不同码流的ts文件,实现自适应码流 的作用,客户端根据播放进度和下载速度进行自行选择。并且ts文件可以部署在cdn服务器上,服务器只需要提供m3u8文件,大大减小了服务器的压力。

那么ts文件格式到底是怎样的呢?
ts和mp4一样都是视频流封装格式,而不是编码技术,其内部 封装的视频流
视频编码是H.264,音频是AAC,MP3, AC-3或者EC-3格式。
MPEG-TS
mpeg2-ts格式,ts(Transport Stream)主要用于视频传输用。mpeg2定义两种流封装格式:
-
PS (Program Stream)节目流:用于存储固定时长的视频,如光盘,
-
TS(Transport Stream)主要用于实时传送的节目。通常TS流的后缀是.ts、.mpg或者.mpeg
TS文件(码流)可以分为三层。
-
TS层(Transport Stream):最外层的封装格式,流识别和传输的信息。
-
PES层(Packet Elemental Stream):音视频数据+时间戳。
-
ES层(Elementary Stream):音视频数据。
4.1 TS层
TS层分为三个部分:TS Header、Adaptation Field、Payload。每个ts报文长度是188字节。
TS Header固定4个字节,Adaptation Field是可选的,主要作用是给不足188字节的数据做填充;其中Payload保存的是PES数据。

ts header中关键的字段如下:
- PID
表示报文类型,包括:PAT、CAT、NIT、PMT、以及媒体数据。其中比较重要的是PAT表和PMT表。 PID值如下,如果PID不是下表中的值,表示的是节目的唯一标识。

解析TS流要先找到PAT表,只要找到PAT就可以找到PMT,然后就可以找到音视频流了。
PAT表和PMT表需要定期插入TS流,因为用户随时可能加入TS流,这个间隔很小,通常每隔几个视频帧就要加入PAT和PMT。其中,PAT和PMT是必须的,还可以加入其他表如SDT(业务描述表)等,不过,HLS流只要PAT和PMT就可以了。
- PCR
PCR是时钟参考。
- PAT表
节目关联表(Program Association Table, PAT),对应的是以前电视节目直播,用来描述ts流中有几个节目。
- PMT表
节目映射表(PMT)的意义在于它给出了节目号与组成这个节目元素之间的映射,也就是说PMT是连接节目号与节目元素的桥梁。
我们知道一个电视节目至少包含了视频和音频数据,而每一个节目的视音频数据都是以包的形式在TS流中传输的,所以说一个TS流包含了多个节目的视频和音频数据包。
节目映射表的 PID 是由 PAT 表提供给出的,表征一路节目所有流信息,包含:VideoPID、AudioPID、DataPID。
- adaptation field
在一个帧的第一个ts包和最后一个ts包中,中间的ts不加。
4.2 PES层
PES层是在每一个视频/音频帧上加入了时间戳等信息,PES的帧头如下:

主要有两个时间戳:
- pts:显示时间戳
- dts:解码时间戳
视频数据两种时间戳都需要,音频只需要pts。pts和dts是由于h.264中的B帧引入的,B帧需要前后帧都进行参考然后进行解码,所以解码时间戳比显示时间戳会提前一点,而I帧和P帧都是只依赖之前的帧,所以pts和dts是一样的。
点播视频dts算法
dts = 初始值 + 90000 / video_frame_rate,初始值可以随便指定,但是最好不要取0,video_frame_rate就是帧率,比如23、30。pts和dts是以timescale为单位的,1s = 90000 time scale , 一帧就应该是90000/video_frame_rate 个timescale。用一帧的timescale除以采样频率就可以转换为一帧的播放时长。
4.3 ES层
ES层是具体的音视频数据,如视频的H.264,音频的AAC。

打包视频流h.264s时需要加上nalu层(Network Abstraction Layer unit),nalu包括start code和nalu header,start code固定为0x00000001(帧开始)或0x000001(帧中)。h.264的数据是由slice组成的,slice的内容包括:视频、sps、pps等。nalu type决定了后面的h.264数据内容。而音频数据则要加上adts(Audio Data Transport Stream)头。
- TS 流生成流程
将原始音视频数据压缩之后,压缩结果组成一个基本码流(ES)。
对ES(基本码流)进行打包形成PES。
在PES包中加入时间戳信息(PTS/DTS)。
将PES包内容分配到一系列固定长度的传输包(TS Packet)中。
在传输包中加入定时信息(PCR)。
在传输包中加入节目专用信息(PSI) 。
连续输出传输包形成具有恒定比特率的MPEG-TS流。
- TS 流解析流程
复用的MPEG-TS流中解析出TS包;
从TS包中获取PAT及对应的PMT;
从而获取特定节目的音视频PID;
通过PID筛选出特定音视频相关的TS包,并解析出PES;
从PES中读取到PTS/DTS,并从PES中解析出基本码流ES;
将ES交给解码器,获得压缩前的原始音视频数据。
五、m3u8和mp4转换
可以使用ffmpeg工具对mp4和m3u8文件之间互相转换。
5.1 mp4转m3u8
ffmpeg 可以将mp4生成m3u8文件和ts文件命令如下:
ffmpeg -re -i 好汉歌.mp4 -c copy -f hls -bsf:v h264_mp4toannexb output.m3u8
因为ffmpeg 默认的list size 为5,所以只获得最后的5个片段。为了解决这个问题,需要指定参数-hls_list_size 0,这样就能包含所有的片段
ffmpeg -re -i 好汉歌.mp4 -c copy -f hls -hls_list_size 0 -bsf:v h264_mp4toannexb output.m3u8
hls_time参数用于设置M3U8列表中切片的duration。
hls_base_url: 指定网络路径,可以用于网络上的m3u8文件。
5.2 m3u8转mp4
tips:m3u8 可能需要key,ffmepg命令将m3u8转成mp4。
ffmpeg -i https://vip.ffzy-online4.com/20230224/10825_cf435d2c/index.m3u8?sign=30db3fb63fd9b8e8edc7d1c02785f9d2 -c copy xiaoaojianghu_43.mp4
六、HLS vs RTSP
关于实时直播,第一时间会想到使用最多的RTSP,那么HLS和RTSP有什么区别呢?
6.1 RTSP(Real Time Streaming Protocol)
RTSP的工作原理:
- 建立连接 : 播放器向流媒体服务器发起 RTSP 连接(例如
rtsp://server.com/stream)。 - 协商参数(DESCRIBE, SETUP): 通过 RTSP 命令,客户端和服务器协商传输参数(如视频编码、传输协议)。
- 传输数据(PLAY) : 客户端发送
PLAY命令后,服务器开始通过 RTP 协议(通常基于 UDP)将流数据包源源不断地推送给客户端。同时,RTCP协议用于传输控制信息(如网络状况反馈)。 - 控制播放(PAUSE, TEARDOWN): 客户端可以通过 RTSP 命令暂停或终止流。
优点:
- 低延迟: 由于是实时的数据流推送,几乎没有切片和缓冲带来的延迟,非常适合实时交互场景。
- 高效率: 基于 UDP 的 RTP 传输避免了 TCP 的重传机制,在良好网络下延迟更稳定。
- 支持点对点控制: 原生支持播放、暂停、快进等 VCR 式操作。
缺点:
- 兼容性差: 现代网页浏览器(Chrome, Firefox, Safari)都不再原生支持 RTSP,需要借助 Flash、浏览器插件或将流转码为 HLS/MPEG-DASH 才能在网页中播放。
- 防火墙/NAT 穿透困难: RTSP/RTP 使用非标准端口或动态端口,在企业防火墙或 NAT 后很容易被阻挡。
- 不支持自适应码率: RTSP 本身没有内置自适应码率切换机制,需要依赖外部系统(如监控领域的流媒体服务器)来实现多码率切换。
6.2 HLS 和 RTSP对比
HLS 是为"分发"和"兼容性"而生的互联网协议,而 RTSP 是为"实时"和"控制"而生的专业流媒体协议。
| 特性 | HLS | RTSP |
|---|---|---|
| 全称 | HTTP Live Streaming | Real Time Streaming Protocol |
| 核心原理 | 将视频切片成小文件(.ts),通过HTTP下载播放 | 建立专有连接,实时传输流数据(如RTP) |
| 协议基础 | HTTP(基于TCP) | RTSP、RTP、RTCP(通常基于UDP,也可用TCP) |
| 延迟 | 高(通常10-30秒或更高) | 低(通常1-3秒,可低于500毫秒) |
| 适应性 | 极强,天生支持自适应码率(ABR) | 弱,通常需要外部系统支持 |
| 防火墙/NAT穿透 | 极佳(使用标准HTTP 80/443端口) | 较差(使用动态端口范围,容易被防火墙阻挡) |
| 主要应用场景 | 点播视频(优酷、YouTube)、直播(Twitch)、广播电视 | 视频监控(IPCAM)、视频会议、移动应用(如FaceTime) |
| 兼容性 | 极佳,所有现代浏览器、移动设备、智能电视都原生支持 | 较差,浏览器不原生支持,需要插件或转码 |
应用场景
- 选择 HLS 的情况:
- 主流互联网视频点播和直播(如 YouTube, Bilibili, Twitch)。
- 需要覆盖最广泛的终端用户(通过浏览器、手机App、智能电视直接观看)。
- 网络环境复杂多变,需要自适应码率来保证用户体验。
- 对延迟不敏感(延迟在10-20秒可接受)。
- 选择 RTSP 的情况:
- 视频监控系统(IPCAM): 这是 RTSP 目前最主流的应用领域,需要低延迟查看实时画面。
- 视频会议或视频聊天(如某些移动端应用): 极低的延迟是关键。
- 专网或局域网内的流媒体应用,可以控制网络环境,避免防火墙问题。
- 需要与旧有流媒体系统集成。
发展趋势
- HLS 是当今互联网公网传输的绝对主流,并且通过低延迟技术不断优化其短板。
- RTSP 在特定领域(如安防、物联网)依然不可替代,但在公共互联网领域已被基于 HTTP 的协议(如 HLS 和 MPEG-DASH)所取代。
- WebRTC作为另一个低延迟协议,在实时通信(如视频会议、在线教育)领域正挑战着 RTSP 的地位,因为它能直接在浏览器中运行。
七、电视迷视频下载实战
作为一个程序员以及一个爱刷剧的仔,怎么实现刷剧自由呢?电视迷网站上有很多好剧,不过可能存在因为下架的风险,以及中间会插入一些澳门菠菜网站的广告,那作为程序员的我,职业病就犯了,爬它。让我们在回顾一下爬虫的关键步骤:
1)网页分析
2)url提取和关键元素匹配
3)保存资源
网页分析是关键,此网站也是使用m3u8文件来保存视频的。
7.1 网页分析
https://dsmi.cc/tvb/XiaoAoJiangHu/yunbo-1-43.html
每一集视频都是yunbo-1-集数.html 的url链接,可以使用遍历的方式进行爬取,这个具体的网页内容分析:
- yunbo-1-43.html 分析
从网页中获取视频链接,如下位置:
<script>var vt={"id":"28","tid":"0","jid":"42","nid":"43","tit":"笑傲江湖(96版)国语","v_name":"tvb","uid":"https://vip.ffzy-online4.com/share/c0a3eab00393c89313e8109bb6504a68","cid":"yunbo","nuid":"","ncid":"","jtit":"第43集","njtit":"","mulu":"XiaoAoJiangHu","zxyj":"/tvb/XiaoAoJiangHu/yunbo-1-43.html","v_note":"43"};
</script>
其中uid 表示链接url,但不是具体的视频文件,是一个base_url。
https://vip.ffzy-online4.com/share/c0a3eab00393c89313e8109bb6504a68
- 获取m3u8
以下js脚本中定义m3u8文件url,是一个相对地址。
<script type="text/javascript">
var video_player= 'artplayer'
var tracker_url = ''
var signaler_url = ''
var auto_play = ''
var hosts = '';
var redirecturl = "http://vip.okzybo.com";
var videoid = "c0a3eab00393c89313e8109bb6504a68";
var id = 'c0a3eab00393c89313e8109bb6504a68'
var l = ''
var r= ''
var t= '15'
var d= ''
var u= ''
var main = "/20230224/10825_cf435d2c/index.m3u8?sign=30db3fb63fd9b8e8edc7d1c02785f9d2";
var xml = "/20230224/10825_cf435d2c/index.xml?sign=30db3fb63fd9b8e8edc7d1c02785f9d2";
var pic = "/20230224/10825_cf435d2c/1.jpg";
var thumbnails = "/20230224/10825_cf435d2c/thumbnails.jpg";
</script>
var main = "/20230224/10825_cf435d2c/index.m3u8?sign=30db3fb63fd9b8e8edc7d1c02785f9d2";
这里m3u8文件路径是一个相对路径,需要加上上数的base_url才是m3u8文件绝对路径。
7.2 爬虫方案
1)使用idx++遍历方式,基于yunbo-1-xxx.htm找到每一集的url。
2)具体页面html分析,使用etree html选择器匹配找到对应的m3u8文件。
<script>var vt={"id":"28","tid":"0","jid":"42","nid":"43","tit":"笑傲江湖(96版)国语","v_name":"tvb","uid":"https://vip.ffzy-online4.com/share/c0a3eab00393c89313e8109bb6504a68","cid":"yunbo","nuid":"","ncid":"","jtit":"第43集","njtit":"","mulu":"XiaoAoJiangHu","zxyj":"/tvb/XiaoAoJiangHu/yunbo-1-43.html","v_note":"43"};
3)var vt使用正则表达式匹配内容,然后转成json数组。
ret = re.match(pattern, str)
注意使用非贪婪算法.*?
- index.m3u8
拼接得出的m3u8文件路径:
https://vip.ffzy-online4.com/20230224/10825_cf435d2c/2000k/hls/mixed.m3u8
下载index.m3u8文件内容如下:
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=800000,RESOLUTION=1080x608
2000k/hls/mixed.m3u8
7.3 解析index.m3u8
mixed.m3u8中才保存的是具体的是ts链接。
2000k/hls/mixed.m3u8
不用解析index.m3u8文件,直接把url中的index.m3u8替换为mixed.m3u8即可,然后mixed.m3u8文件。
-
使用python下载http文件
import urllib.request
url = 'http://example.com/file.txt'
save_path = 'path/to/save/file.txt'urllib.request.urlretrieve(url, save_path)
print('文件已下载到', save_path)
方法2:
import requests
url = 'http://example.com/file.txt'
save_path = 'path/to/save/file.txt'
response = requests.get(url)
with open(save_path, 'wb') as file:
file.write(response.content)
print('文件已下载到', save_path)
7.4 解析mixed.m3u8
mixed.m3u8内容格式如下,其中的ts的url是没有索引的,所以下载后需要增加绝对路径地址。
#EXTINF:1.520000,
0a8acd2744d000118.ts
#EXT-X-DISCONTINUITY
#EXTINF:6.666667,
0a8acd2744d0577670.ts
#EXTINF:3.333333,
0a8acd2744d0577671.ts
#EXTINF:3.333333,
0a8acd2744d0577672.ts
#EXTINF:5.366667,
0a8acd2744d0577673.ts
#EXTINF:1.300000,
0a8acd2744d0577674.ts
#EXT-X-DISCONTINUITY
#EXTINF:6.800000,
0a8acd2744d000119.ts
#EXTINF:1.800000,
0a8acd2744d000120.ts
#EXTINF:5.840000,
0a8acd2744d000121.ts
添加后的ts路径:
https://vip.ffzy-online4.com/20230224/10825_cf435d2c/2000k/hls/0a8acd2744d000006.ts
7.5 去菠菜广告视频
视频中有菠菜广告视频,需要分析ts将其删除。
ts分析
78e8d4b1bb1000115.ts
78e8d4b1bb1000116.ts
78e8d4b1bb1000117.ts
78e8d4b1bb1000118.ts
78e8d4b1bb10359685.ts
78e8d4b1bb10359686.ts
78e8d4b1bb10359687.ts
78e8d4b1bb10359688.ts
78e8d4b1bb10359689.ts
分析ts文件,正常视频文件名都是递增连续的,但是中间有一些ts文件名不是连续的,且值超过了一定范围,确认这些确实是广告视频,从ts中删掉即可。
tips:python编码技巧:re.S匹配换行符,支持多行匹配。
re.findall(r"a(\d+)b.+a(\d+)b", str, re.S)
#s输出[('23', '34')]
完整代码如下:
# -*-coding:utf8-*-
import requests
import lxml
from lxml import etree
import os
import base64
import re
import time
import socket
import urllib
#timeout = 20
#socket.setdefaulttimeout(timeout)
video_name="XiaoAoJiangHu"
http_headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.41",
}
def parse_m3u8(idx, url):
#cmd = "ffmpeg -i %s -c copy %s_%d.mp4" % (url, video_name, idx)
#os.system(cmd)
print(url)
base_url = os.path.dirname(url)
mixed_url = base_url + "/2000k/hls/mixed.m3u8"
print(mixed_url)
page = requests.get(mixed_url, headers=http_headers)
page.encoding = "utf-8"
mix_m3u8_content = str(page.content, encoding='utf-8')
#print("===========" + mix_m3u8_content)
#len_cnt = [0 for _ in range(100)]
maxlen = 0;
ts_list = re.findall(".*?\.ts", mix_m3u8_content)
for ts in ts_list:
if (maxlen < len(ts)):
maxlen = len(ts)
print("max ts len:%d" % maxlen)
lajits_list = []
for ts in ts_list:
if (maxlen == len(ts)):
lajits_list.append(ts)
print("lajits:")
for lajits in lajits_list:
print(lajits)
ts_list = re.findall("#EXTINF:.*?\.ts", mix_m3u8_content, re.S)
for ts in ts_list:
for lajits in lajits_list:
if lajits in ts:
print("lajits:")
print(ts)
mix_m3u8_content = mix_m3u8_content.replace(ts, "")
with open("mixd.m3u8", "w") as mixfile:
mixfile.write(mix_m3u8_content)
#save_path = "mixed.m3u8"
#urllib.request.urlretrieve(mixed_url, save_path)
#print('文件已下载到', save_path)
def parseVideoPage(idx, url):
page = requests.get(url, headers=http_headers)
page.encoding = "utf-8"
html = page.text
#print(html)
selector = etree.HTML(html)
script = selector.xpath('//script/text()')
print("script:", script[0])
ret = re.findall("var main = (.*?);", script[0])
print("ret=", ret[0])
page.close()
m3u8_url = ret[0]
# TODO : fix me
m3u8_url = m3u8_url.replace('\"', '')
parse_m3u8(idx, "https://vip.ffzy-online4.com/" + m3u8_url)
return
def parseHomePage(idx, url):
page = requests.get(url, headers=http_headers)
page.encoding = "utf-8"
html = page.text
#print(html)
selector = etree.HTML(html)
script = selector.xpath('//script/text()')
print("script:", script[0])
ret = re.findall("\"uid\":(.*?),", script[0])
print("ret=", ret[0])
page.close()
video_url = ret[0]
video_url = video_url.replace('"', '')
print("video_url=", video_url)
parseVideoPage(idx, video_url)
return
if __name__ == '__main__':
for idx in range(1,44):
parseHomePage(idx, "https://dsmi.cc/tvb/XiaoAoJiangHu/yunbo-1-%d.html" % idx)
#parseHomePage("https://dsmi.cc/tvb/XiaoAoJiangHu/yunbo-1-43.html")
#parseVideoPage("https://vip.ffzy-online4.com/share/c0a3eab00393c89313e8109bb6504a68")
#parse_m3u8("https://vip.ffzy-online4.com/20230224/10825_cf435d2c/index.m3u8?sign=30db3fb63fd9b8e8edc7d1c02785f9d2")
八、参考链接
m3u8文件介绍:
https://www.cnblogs.com/renhui/p/10351870.html
https://www.cnblogs.com/mq0036/p/14961793.html
https://zhuanlan.zhihu.com/p/162947124
https://www.makeuseof.com/what-is-an-m3u8-file-how-to-open-it/
hls协议介绍:
https://datatracker.ietf.org/doc/html/draft-pantos-http-live-streaming-23
https://www.cnblogs.com/heluan/p/8944319.html
ts相关链接:
https://zhuanlan.zhihu.com/p/520985863
https://zhuanlan.zhihu.com/p/608579756
m3u8文件下载:
https://blog.csdn.net/chy_18883701161/article/details/118884565