当前位置: 首页 > news >正文

M3U8流视频数据爬虫

M3U8流视频数据爬虫

HLS技术介绍

现在大部分视频客户端都采用HTTP Live Streaming(HLS,Apple为了提高流播效率开发的技术),而不是直接播放MP4等视频文件。HLS技术的特点是将流媒体切分为若干【TS片段】(比如几秒一段),然后通过一个【M3U8列表文件】将这些TS片段批量下载供客户端播放器实现实时流式播放。因此,在爬取HLS的流媒体文件的思路一般是先【下载M3U8文件】并分析其中内容,然后在批量下载文件中定义的【TS片段】,最后将其【组合】成mp4文件或者直接保存TS片段。

M3U8文件详解

如果想要爬取HLS技术下的资源数据,首先要对M3U8的数据结构和字段定义非常了解。M3U8是一个扩展文件格式,由M3U扩展而来。那么什么是M3U呢?

M3U文件

M3U这种文件格式,本质上说不是音频视频文件,它是音频视频文件的列表文件,是纯文本文件。

M3U这种文件被获取后,播放软件并不是播放它,而是根据它的记录找到媒体的网络地址进行在线播放。也就是说,M3U格式的文件只是存储多媒体播放列表,并提供了一个指向其他位置的音频视频文件的索引,播放的是那些被指向的文件。

为了能够更好的理解M3U的概念,我们先简单做一个M3U文件(myTest.m3u)。在电脑中随便找几个MP3,MP4文件依次输入这些文件的路径,myTest.m3u文件内容如下

E:\Users\m3u8\刘德华 - 无间道.mp4
E:\Users\m3u8\那英 - 默.mp3
E:\Users\m3u8\周杰伦 - 不能说的秘密.mp4
E:\Users\m3u8\花粥 - 二十岁的某一天.mp3
E:\Users\m3u8\周深 - 大鱼.mp4
M3U8文件

M3U8也是一种M3U的扩展格式(高级的M3U,所以也属于M3U)。

**M3U8示例:**大家会看到在该文件中有大量的ts文件的链接地址,这个就是我们之前描述的真正的视频文件。其中任何一个ts文件都是一小段视频,可以单独播放。我们做视频爬虫的目标就是把这些ts文件都爬取下来。

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:3.127,
/20230512/RzGw5hDB/1500kb/hls/YZefAiEF.ts
#EXTINF:3.127,
/20230512/RzGw5hDB/1500kb/hls/FsliUCL6.ts
#EXTINF:3.127,
/20230512/RzGw5hDB/1500kb/hls/DD7c47bz.ts
#EXT-X-ENDLIST
实战
需求:
  • https://www.mjtt5.tv/
具体操作
  1. 进入视频播放页
  2. 点击播放按钮,定位ts数据包,从中提取ts片段的url,探究url的规律
  3. 打开抓包工具,刷新页面,全局搜索m3u8定位到找到m3u8文件
  4. 解析m3u8文件提取文件中ts片段链接
  • 同步操作代码
import requests
from urllib.parse import urljoin
import re
import os
dirName = 'tsLib'
if not os.path.exists(dirName):os.mkdir(dirName)headers  = {'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36'
}
#m3u8地址
url = "https://cdn13.tvtvgood.com/202310/20/c1959422deee/playlist.m3u8?token=d5i9GCr3ljqGsSf48-aG2w&expires=1698221543"
page_text = requests.get(url=url,headers=headers).text
page_text = page_text.strip()#解析出每一个ts切片的地址
ts_url_list = []
for line in page_text.split('\n'):if not line.startswith('#'):ts_url = line#不同ts下载地址ts_url = 'https://cdn13.tvtvgood.com/202310/20/c1959422deee/'+ts_urlts_url_list.append(ts_url)print(ts_url_list)
#请求到每一个ts切片的数据
for url in ts_url_list:#获取ts片段的数据ts_data = requests.get(url=url,headers=headers).contentts_name = url.split('/')[-1]ts_path = dirName+'/'+ts_namewith open(ts_path,'wb') as fp:#需要将解密后的数据写入文件进行保存fp.write(ts_data)print(ts_name,'下载保存成功!')# ts文件的合并,最好网上找专业的工具进行合并,自己手动合并会经常出问题
  • 异步操作代码:协程
#https://cdn8.tvtvgood.com/202206/21/6abfb3237d01/playlist8.ts
#https://cdn8.tvtvgood.com/202206/21/6abfb3237d01/playlist7.ts
import requests
import os
import asyncio
import aiohttp
from threading import Thread
dirName = 'tsLib'
if not os.path.exists(dirName):os.mkdir(dirName)headers  = {'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36'
}
#m3u8文件的url
m3u8_file_url = 'https://cdn8.tvtvgood.com/202206/21/6abfb3237d01/playlist.m3u8?token=9vVIuesP2MAZ4G1V6y6DnA&expires=1698927688'
m3u8_text = requests.get(url=m3u8_file_url,headers=headers).textts_url_list = [] #存储解析出来的每一个ts片段的url
for line in m3u8_text.split('\n'):if not line.startswith('#'):ts_url = linets_url = 'https://cdn8.tvtvgood.com/202206/21/6abfb3237d01/'+ts_urlts_url_list.append(ts_url)#基于协程实现异步的ts片段的请求
async def get_reqeust(url):#参数url就是ts片段的请求urlasync with aiohttp.ClientSession() as req:async with await req.get(url=url,headers=headers) as response:ts_data = await response.read()dic = {'ts_data':ts_data,'ts_title':url.split('/')[-1]}return dicdef save_ts_data(t):dic = t.result()ts_data = dic['ts_data']ts_title = dic['ts_title']ts_path = dirName + '/' + ts_titlewith open(ts_path,'wb') as fp:fp.write(ts_data)print(ts_title,':保存下载成功!')tasks = []
for url in ts_url_list:c = get_reqeust(url)task = asyncio.ensure_future(c)task.add_done_callback(save_ts_data)tasks.append(task)loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))#使用协程:实现一定得有一个url列表,遍历该列表进行多协程的创建
#使用多个loop的场景:两种数据资源下载,需要实现有两个url列表
#问题:两个loop之间的关系是异步的吗?
#注意:千万别搞loop的嵌套。#特殊的方式:创建两个线程,两个线程中封装处理两个loop。

线程池的实现方案:

#https://cdn8.tvtvgood.com/202206/21/6abfb3237d01/playlist8.ts
#https://cdn8.tvtvgood.com/202206/21/6abfb3237d01/playlist7.ts
import requests
import os
from threading import Thread
from multiprocessing.dummy import PooldirName = 'tsLib'
if not os.path.exists(dirName):os.mkdir(dirName)headers  = {'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36','Connection':'closed'
}
#m3u8文件的url
m3u8_file_url = 'https://cdn8.tvtvgood.com/202206/21/6abfb3237d01/playlist.m3u8?token=9vVIuesP2MAZ4G1V6y6DnA&expires=1698927688'
m3u8_text = requests.get(url=m3u8_file_url,headers=headers).textts_url_list = [] #存储解析出来的每一个ts片段的url
for line in m3u8_text.split('\n'):if not line.startswith('#'):ts_url = linets_url = 'https://cdn8.tvtvgood.com/202206/21/6abfb3237d01/'+ts_urlts_url_list.append(ts_url)def get_reqeust(url):#参数url就是ts片段的请求urlts_data = requests.get(url=url,headers=headers,verify=False).contentts_path = dirName + '/' + url.split('/')[-1]with open(ts_path,'wb') as fp:fp.write(ts_data)print(ts_path,':保存下载成功!')#HTTPSConnectionPool异常原因:#网络请求的并发量太大(减少并发or在headers中添加一个Connection:closed)pool = Pool(100)
pool.map(get_reqeust,ts_url_list)

相关文章:

M3U8流视频数据爬虫

M3U8流视频数据爬虫 HLS技术介绍 现在大部分视频客户端都采用HTTP Live Streaming(HLS,Apple为了提高流播效率开发的技术),而不是直接播放MP4等视频文件。HLS技术的特点是将流媒体切分为若干【TS片段】(比如几秒一段…...

保护您的数字财富:模块化沙箱在源代码防泄露中的突破

在数字化浪潮中,企业面临着前所未有的数据安全挑战。源代码、商业机密、客户数据……这些宝贵的数字资产一旦泄露,后果不堪设想。SDC沙盒防泄密系统,以其卓越的技术实力和创新的解决方案,为企业提供了一个坚不可摧的安全屏障。 核…...

FFmpeg源码:avio_r8、avio_rl16、avio_rl24、avio_rl32、avio_rl64函数分析

一、引言 AVIOContext是FFmpeg(本文演示用的FFmpeg源码版本为5.0.3)中的字节流上下文结构体,用来管理输入输出数据。打开一个媒体文件的时候,需要先把数据从硬盘读到缓冲区,然后会用到AVIOContext中的如下成员&#x…...

如何使用 API 查看极狐GitLab 镜像仓库中的镜像?

GitLab 是一个全球知名的一体化 DevOps 平台,很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab :https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版,专门为中国程序员服务。可以一键式部署…...

软件-vscode-plantUML-IDEA

文章目录 vscode基础命令 实操1. vscode实现springboot项目搭建 (包括spring data jpa和sqlLite连接) PlantUMLIDEA下载及安装Eval Reset插件配置修改IDEA创建项目的默认目录IDEA配置gitIDEA翻译插件translationIDEA断点调试IDEA全局搜索快捷键不能使用代…...

ES6语法详解,面试必会,通俗易懂版

目录 Set的基本使用WeakSet 使用Set 和 WeakSet 区别内存泄漏示例:使用普通 Set 保存 DOM 节点如何避免这个内存泄漏MapWeakMap 的使用 Set的基本使用 在ES6之前,我们存储数据的结构主要有两种:数组、对象。 在ES6中新增了另外两种数据结构&a…...

CTFshow--Web--代码审计

目录 web301 web302 web303 web304 web305 web306 web307 web308 web309 web310 web301 开始一个登录框, 下意识sql尝试一下 发现 1 的时候会到一个 checklogin.php 的路径下, 但啥也没有 好吧, 这是要审计代码的 ,下载好源码, 开始审计 看了一下源码 , 应该就是sql…...

Java语言程序设计——篇十(1)

🌿🌿🌿跟随博主脚步,从这里开始→博主主页🌿🌿🌿 接口介绍 接口概述接口定义接口的实现实战演练 👅接口的继承实战演练实战演练 接口的类型常量实战演练 静态方法默认方法解决默认方…...

Qt对比MFC优势

从Qt小白到现在使用了有四年的时间,之前也搞过MFC,WinForm,基本上都是桌面的框架, 从难易程度看MFC>QT>WinForm; 运行的效率上来看MFC>QT>WinForm; 开发效率上WinForm>QT>MFC; 跨平台Qt首选; 界面的美观难易程度Qt>…...

RuntimeError: No CUDA GPUs are available

RuntimeError: No CUDA GPUs are available 目录 RuntimeError: No CUDA GPUs are available 【常见模块错误】 【解决方案】 解决步骤如下: 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页,我是博主英杰,211科…...

URL参数中携带中文?分享 1 段优质 JS 代码片段!

本内容首发于工粽号:程序员大澈,每日分享一段优质代码片段,欢迎关注和投稿! 大家好,我是大澈! 本文约 800 字,整篇阅读约需 1 分钟。 今天分享一段优质 JS 代码片段,在发送 ajax 请…...

sass的使用

一、变量 //声明一个变量 $highlight-color: #F90; .selected {border: 1px solid $highlight-color; }//编译后 .selected {border: 1px solid #F90; }二、导入 import "xxx.scss"三、混合器简单定义 通过mixin定义,通过include调用 // mixin.scss /…...

【足球走地软件】走地数据分析预测【大模型篇】走地预测软件实战分享

了解什么是走地数据? 走地数据分析,在足球赛事的上下文中,是一种针对正在进行中的比赛进行实时数据分析的方法。这种方法主要用于预测比赛中的某些结果或趋势,如总进球数、比分变化、球队表现等。 在足球走地数据分析中&#xf…...

现在有什么赛道可以干到退休?

最近,一则“90后无论男女都得65岁以后退休”的消息在多个网络平台流传,也不知道是真是假,好巧不巧今天刷热点的时候又看到一条这样的热点:现在有什么赛道可以干到退休? 点进去看了几条热评,第一条热评说的…...

c程序杂谈系列(职责链模式与if_else)

从处理器的角度来说,条件分支会导致指令流水线的中断,所以控制语句需要严格保存状态,因为处理器是很难直接进行逻辑判断的,有可能它会执行一段时间,发现出错后再返回,也有可能通过延时等手段完成控制流的正…...

前端开发技术之CSS(层叠样式表)

盒模型(Box Model) CSS盒模型描述了如何计算一个元素的总宽度和高度。 它包括以下几个部分: 1. 内容(Content):元素的实际内容,比如文本或图片。 2. 内边距(Padding)&…...

go语言day20 使用gin框架获取参数 使用自定义的logger记录日志

Golang 操作 Logger、Zap Logger 日志_golang zap-CSDN博客 目录 一、 从控制器中获取参数的几种形式 1) 页面请求url直接拼接参数。 2) 页面请求提交form表单 3) 页面请求发送json数据,使用上下文对象c的BindJSON()方法接…...

DHCP笔记

DHCP---动态主机配置协议 作用:为终端动态提供IP地址,子网掩码,网关,DNS网址等信息 具体流程 报文抓包 在DHCP服务器分配iP地址之间会进行广播发送arp报文,接收IP地址的设备也会发送,防止其他设备已经使用…...

TCP为什么需要四次挥手?

tcp为什么需要四次挥手? 答案有两个: 1.将发送fin包的权限交给被动断开发的应用层去处理,也就是让程序员处理 2.接第一个答案,应用层有了发送fin的权限,可以在发送fin前继续向对端发送消息 为了搞清楚这个问题&…...

MySQL 索引相关基本概念

文章目录 前言一. B Tree 索引1. 概念2. 聚集索引/聚簇索引3. 辅助索引/二级索引4. 回表5. 联合索引/复合索引6. 覆盖索引 二. 哈希索引三. 全文索引 前言 InnoDB存储引擎支持以下几种常见索引:BTree索引,哈希索引,全文索引 一. B Tree 索引…...

golang循环变量捕获问题​​

在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下: 问题背景 看这个代码片段: fo…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

AI,如何重构理解、匹配与决策?

AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...

【笔记】WSL 中 Rust 安装与测试完整记录

#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...