音视频处理(三):hls协议和m3u8详解和视频下载爬虫实战

音视频处理(三):hls协议和m3u8详解和视频下载爬虫实战

文章目录

  • 一、背景
  • 二、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视频流

工作原理:

  1. 切片(Segmentation): 视频源(如直播流或点播文件)被编码器实时地切割成一系列小的、连续的 TS 格式视频文件片段(例如每个片段时长2-10秒)。
  2. 创建索引(Playlist): 同时,编码器会生成一个不断更新的索引文件(M3U8 格式的播放列表)。这个文件记录了所有 TS 片段的URL和元数据(如码率、分辨率)。
  3. 分发(Distribution): 这些 TS 片段和 M3U8 文件通过标准的 HTTP 服务器分发,就像分发普通的网页图片一样。
  4. 播放(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的文件的一些注意事项:

  1. 分片必须是动态改变的,序列不能相同,并且序列必须是增序的。
  2. 当M3U8没有出现EXT-X-ENDLIST标签时,无论这个M3U8列表中有多少分片,播放分片都是从倒数第三片开始播放,如果不满三片则不应该播放。当然如果有些播放器做了特别定制了,则可以不遵照这个原则。
  3. 以播放当前分片的duration时间刷新M3U8列表,然后做对应的加载动作。
  4. 前一片分片和后一片分片有不连续的时候,播放可能会出错,那么需要X-DISCONTINUTY标签来解决这个错误。
  5. 如果播放列表在刷新之后与之前的列表相同,那么在播放当前分片duration一半的时间内在刷新一次。
  • 扩展的m3u8属性EXT-X-STREAM-INF

EXT-X-STREAM-INF标签出现在M3U8时,主要是出现在多级M3U8文件中时,例如M3U8中包含子M3U8列表,或者主M3U8中包含多码率M3U8时;该标签后需要跟一些属性,下面就来逐一说明一下这些属性:

  1. BANDWIDTH:BANDWIDTH的值为最高码率值,当播放EXT-X-STREAM-INF下对应的M3U8时占用的最大码率(必要参数)。
  2. AVERAGE-BANDWIDTH:AVERAGE-BANDWIDTH的值为平均码率值,当播放EXT-X-STREAM-INF下对应的M3U8时占用的平均码率。(可选参数)。
  3. CODECS:CODECS的值用于声明EXT-X-STREAM-INF下面对应M3U8里面的音视频编码、视频编码的信息(可选参数)。
  4. RESOLUTION:M3U8中视频的宽高信息描述(可选参数)。
  5. 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的工作原理:

  1. 建立连接: 播放器向流媒体服务器发起 RTSP 连接(例如 rtsp://server.com/stream)。
  2. 协商参数(DESCRIBE, SETUP): 通过 RTSP 命令,客户端和服务器协商传输参数(如视频编码、传输协议)。
  3. 传输数据(PLAY): 客户端发送 PLAY命令后,服务器开始通过 RTP协议(通常基于 UDP)将流数据包源源不断地推送给客户端。同时,RTCP协议用于传输控制信息(如网络状况反馈)。
  4. 控制播放(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 是为“实时”和“控制”而生的专业流媒体协议。

特性HLSRTSP
全称HTTP Live StreamingReal 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 var var var; var redirecturl = "http://vip.okzybo.com"; var videoid = "c0a3eab00393c89313e8109bb6504a68"; var var var var t= '15' var var 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文件绝对路径。

https://vip.ffzy-online4.com/20230224/10825_cf435d2c/index.m3u8?sign=30db3fb63fd9b8e8edc7d1c02785f9d2

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

H.222.0 : Information technology - Generic coding of moving pictures and associated audio information: Systems

m3u8文件下载:

https://blog.ZEEKLOG.net/chy_18883701161/article/details/118884565

Read more

Spring Boot @ConditionalOnMissingBean 误判问题深度解析

Spring Boot @ConditionalOnMissingBean 误判问题深度解析 一、问题现象与核心原因 1.1 典型错误场景 // 场景1:重复Bean定义@ConfigurationpublicclassConfigA{@BeanpublicDataSourcedataSource(){returnnewHikariDataSource();}}@Configuration@ConditionalOnMissingBean(DataSource.class)publicclassConfigB{@BeanpublicDataSourceembeddedDataSource(){returnnewEmbeddedDatabaseBuilder().build();}}// 错误:两个DataSource Bean同时存在// 场景2:误判导致Bean缺失@ConfigurationpublicclassPrimaryConfig{@Bean@Primary// 标记为PrimarypublicMyServiceprimaryService(){returnnewP

By Ne0inhk
Flutter 组件 php_serializer 适配鸿蒙 HarmonyOS 实战:异构数据兼容,构建跨语言协议解析与历史债务治理架构

Flutter 组件 php_serializer 适配鸿蒙 HarmonyOS 实战:异构数据兼容,构建跨语言协议解析与历史债务治理架构

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 php_serializer 适配鸿蒙 HarmonyOS 实战:异构数据兼容,构建跨语言协议解析与历史债务治理架构 前言 在鸿蒙(OpenHarmony)生态迈向全场景数字化转型的背景下,许多企业级应用在接入鸿蒙终端时,往往需要面对存量的、基于 PHP 构建的重型后端遗产系统。这些系统常通过 PHP 特有的 serialize() 协议输出配置数据或持久化对象。在鸿蒙设备这类强调 AOT 静态强类型与高性能 JSON 解析的环境下,如果应用无法直接解析这种带有历史烙印的非标准序列化格式,由于由于前后端数据协议的断层,极易由于由于“协议无法互通”导致鸿蒙应用无法读取核心业务配置或陷入繁杂的中间件转发泥潭。 我们需要一种能够深度解析 PHP 序列化语法、支持嵌套对象恢复且具备纯 Dart 离线运作能力的协议转换方案。 php_serializer 为 Flutter 开发者引入了“跨时空协议桥接”

By Ne0inhk
【MySQL】内置函数和内外连

【MySQL】内置函数和内外连

一. 内置函数 1. 日期函数 current_date(),current_time(),current_timestamp() 描述当前日期,描述当前时间,描述当前时间戳 案例: date_add(date,interval d_value_type),date_sub(date,interval d_value_type) date加上日期,date减去日期 案例: datediff(date1,date2) 两个日期相差天数,date1-date2 案例: 2. 字符串函数 select  charset(列)from  【表】; 查询某张表内列的字符集 案例: select concat('内容&

By Ne0inhk