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
实战
需求:
具体操作
  1. 进入视频播放页
  2. 点击播放按钮,定位ts数据包,从中提取ts片段的url,探究url的规律
  3. 打开抓包工具,刷新页面,全局搜索m3u8定位到找到m3u8文件
  4. 解析m3u8文件提取文件中ts片段链接
  • 同步操作代码
python 复制代码
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_url
        ts_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).content
    ts_name = url.split('/')[-1]
    ts_path = dirName+'/'+ts_name
    with open(ts_path,'wb') as fp:
        #需要将解密后的数据写入文件进行保存
        fp.write(ts_data)
    print(ts_name,'下载保存成功!')

# ts文件的合并,最好网上找专业的工具进行合并,自己手动合并会经常出问题
  • 异步操作代码:协程
python 复制代码
#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).text

ts_url_list = [] #存储解析出来的每一个ts片段的url
for line in m3u8_text.split('\n'):
    if not line.startswith('#'):
        ts_url = line
        ts_url = 'https://cdn8.tvtvgood.com/202206/21/6abfb3237d01/'+ts_url
        ts_url_list.append(ts_url)

#基于协程实现异步的ts片段的请求
async def get_reqeust(url):#参数url就是ts片段的请求url
    async 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 dic

def save_ts_data(t):
    dic = t.result()
    ts_data = dic['ts_data']
    ts_title = dic['ts_title']
    ts_path = dirName + '/' + ts_title
    with 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。

线程池的实现方案:

python 复制代码
#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 Pool


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',
    '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).text

ts_url_list = [] #存储解析出来的每一个ts片段的url
for line in m3u8_text.split('\n'):
    if not line.startswith('#'):
        ts_url = line
        ts_url = 'https://cdn8.tvtvgood.com/202206/21/6abfb3237d01/'+ts_url
        ts_url_list.append(ts_url)

def get_reqeust(url):#参数url就是ts片段的请求url
    ts_data = requests.get(url=url,headers=headers,verify=False).content
    ts_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)
相关推荐
API小爬虫12 分钟前
淘宝按图搜索商品(拍立淘)Java 爬虫实战指南
java·爬虫·图搜索算法
Clown954 小时前
Go语言爬虫系列教程 实战项目JS逆向实现CSDN文章导出教程
javascript·爬虫·golang
天上路人5 小时前
AI神经网络降噪算法在语音通话产品中的应用优势与前景分析
深度学习·神经网络·算法·硬件架构·音视频·实时音视频
小白学大数据5 小时前
Scrapy框架下地图爬虫的进度监控与优化策略
开发语言·爬虫·python·scrapy·数据分析
视频砖家5 小时前
如何设置FFmpeg实现对高分辨率视频进行转码
ffmpeg·音视频·视频编解码·视频转码
咕噜咕噜啦啦6 小时前
python爬虫实战训练
爬虫·python
yanjiee7 小时前
视频质量分析时,遇到不同分辨率的对照视频和源视频,分辨率对齐的正确顺序。
ffmpeg·音视频
hudawei9967 小时前
flutter缓存网络视频到本地,可离线观看
flutter·缓存·音视频
lqj_本人9 小时前
鸿蒙OS&UniApp实现视频播放与流畅加载:打造完美的移动端视频体验#三方框架 #Uniapp
uni-app·音视频·harmonyos
猫猫村晨总11 小时前
网络爬虫学习之httpx的使用
爬虫·python·httpx