草庐IT

Python爬取m3u8格式的视频

Rainist 2023-04-12 原文

声明:本文只作学习研究,禁止用于非法用途,否则后果自负,如有侵权,请告知删除,谢谢!

Python爬取m3u8格式的视频目录

背景

在某一天,群友分享了一些小视频,手机端可以正常观看,但是到了电脑上,输入网址之后会下载下来一个m3u8格式的文件,这就让我犯了难。所以我就研究了一下,并使用Python来将该文件爬取了下来。
参考文章如下:
西北乱跑娃 — python m3u8库
Python 手把手实现M3U8视频抓取
python实战案例:解析m3u8视频文件
python爬取m3u8视频教程

1.文件信息

链接图如下

下载下来呢,也是m3u8文件,一种非常特殊的文件。我们点击查看,就可以查看到
3u8的一些信息
我在这里屏蔽了网址,免得暴露我在下载什么hhhhh

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:2
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="https://h09.t*********wc.com/20220703/9K***sCCV/30**0kb/hls/key.key"
#EXTINF:1.16,
https://h09.*********.com/20220703/9K***V/300**b/hls/Foszl**SV.ts
#EXTINF:1.2,
https://h09.**********.com/20220703/9KR**CV/30**kb/hls/b7tCBoOu.ts

经过查阅资料,该文件的我信息大致如下

# EXTM3U:.m3u8文件的格式定义
# EXT-X-KEY: 密钥的信息
# METHOD: 加密的方法,这里采用的是AES-128的加密方式
# URI: 密钥的地址,需要获取访问得到密钥的信息
# IV: 偏移量,AES加密的方法,通过这个密钥就可以解密,获取正确的视频信息

那什么是m3u8呢?

M3U8 是 Unicode 版本的 M3U,用 UTF-8 编码。“M3U” 和 “M3U8” 文件都是苹果公司使用的 HTTP Live
Streaming(HLS) 协议格式的基础,这种协议格式可以在 iPhone 和 Macbook 等设备播放。

通俗点可以理解为,一个视频文件拆分为多个.ts片段的视频文件,然后将所有的ts合成MP4文件就可以播放了。但是为什么有些在线或者m3u8的播放器会用不了呢?由于大部门的m3u8生成的结果不太一致,与该播放器的解密格式不一样,所以导致打开。

一般来说,在m3u8文件中都会有key以及AES的偏移量IV,我们根据其中的URL来获取他们,之后我们根据m3u8文件中的.ts的文件URL来下载视频片段,解密之后拼接成mp4的文件就行了。

2.构造请求获得m3u8文件

我们已经有了m3u8文件的URL,因此免去了抓包这一项工作。我们直接构造response即可

def get_file(url,count):
    resp=requests.request('GET',url)
    # print(resp.content)
    with open('./m3u8_link/'+str(count)+'.m3u8','wb') as f:
        f.write(resp.content)

3.获得m3u8文件中的key以及偏移量IV

根据我们上一步获得的文件内容,这里我选择使用正则来匹配出来key以及IV对应的URL,之后在构造resp即可获得其内容。
这里要说明一下,我们的m3u8文件中AES加密的时候是没有使用IV的,所以使用时实际上令IV=Key
.*?,经典的正则在爬虫中的使用了。

def get_key(path):
    with open(path, 'rb') as f:
        file_content=str(f.read())
    print(file_content)
    key_link = re.search('URI=\"(.*?)\"', file_content).group(1)
    key=requests.request('GET',key_link).content
    return key

4.获取.ts文件链接

其实这一步也可以使用正则来继续匹配,但是我偷了一点小懒,使用了m3u8库来进行匹配。

import m3u8
def get_ts_list(path):
    m3u8_obj = m3u8.load(path)
    ts_urls = []
    for i, seg in enumerate(m3u8_obj.segments):
        # if i<=100:
            ts_urls.append(seg.uri)
    # print(ts_urls)
    return ts_urls

经过这一步之后,我们就获得了m3u8文件中整个.ts文件对应的URL,接下来只要根据.ts文件对应的URL来获取视频片段,解密之后拼接就可以了。

5.进行解密

解密的库 pip install pycryptodome
就是一些常规的AES解密操作了,我们获得的m3u8文件中没有IV偏移量,这里用使iv=key即可。注意,AES要补0的,补字节0到16的倍数。

from Crypto.Cipher import AES
sprytor = AES.new(key, AES.MODE_CBC,iv)
# 获取ts文件二进制数据
ts = requests.get(ts_url).content
# 密文长度不为16的倍数,则添加b"0"直到长度为16的倍数
# decrypt方法的参数需要为16的倍数,如果不是,需要在后面补二进制"0"
while len(ts) % 16 != 0:
    ts += b"0"
with open(name, "ab") as file:
    file.write(sprytor.decrypt(ts))

6.下载拼接

之后下载以字节流的形式进行拼接就可以了。

def download(ts_urls,key,iv,count,path):
    name=path
    print("视频",count,"需要下载的文件长度为", len(ts_urls))
    for i in range(len(ts_urls)):
        ts_url=ts_urls[i]
        if i%10==0:
            print("视频",count,"当前下载进度:",str(i/len(ts_urls)*100)[:4],'%')
        # 如果连接末尾没有.ts手动加上
        ts_name = ts_url.split("/")[-1] + '.ts'  # ts文件名
        # 解密,new有三个参数,
        # 第一个是秘钥(key)的二进制数据,
        # 第二个使用下面这个就好
        # 第三个IV在m3u8文件里URI后面会给出,如果没有,可以尝试把秘钥(key)赋值给IV
        sprytor = AES.new(key, AES.MODE_CBC,iv)
        # 获取ts文件二进制数据
        ts = requests.get(ts_url).content
        # 密文长度不为16的倍数,则添加b"0"直到长度为16的倍数
        while len(ts) % 16 != 0:
            ts += b"0"
        # 写入mp4文件
        with open(name, "ab") as file:
            # # decrypt方法的参数需要为16的倍数,如果不是,需要在后面补二进制"0"
            file.write(sprytor.decrypt(ts))
    print(name, "下载完成")

其实还可以使用多线程优化,完整项目请见本人的github

有关Python爬取m3u8格式的视频的更多相关文章

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  3. ruby-on-rails - 将 Ruby 中的日期/时间格式化为 YYYY-MM-DD HH :MM:SS - 2

    这个问题在这里已经有了答案:Railsformattingdate(4个答案)关闭4年前。我想格式化Time.Now函数以显示YYYY-MM-DDHH:MM:SS而不是:“2018-03-0909:47:19+0000”该函数需要放在时间中.现在功能。require‘roo’require‘roo-xls’require‘byebug’file_name=ARGV.first||“Template.xlsx”excel_file=Roo::Spreadsheet.open(“./#{file_name}“,extension::xlsx)xml=Nokogiri::XML::Build

  4. ruby - 我可以将我的 README.textile 以正确的格式放入我的 RDoc 中吗? - 2

    我喜欢使用Textile或Markdown为我的项目编写自述文件,但是当我生成RDoc时,自述文件被解释为RDoc并且看起来非常糟糕。有没有办法让RDoc通过RedCloth或BlueCloth而不是它自己的格式化程序运行文件?它可以配置为自动检测文件后缀的格式吗?(例如README.textile通过RedCloth运行,但README.mdown通过BlueCloth运行) 最佳答案 使用YARD直接代替RDoc将允许您包含Textile或Markdown文件,只要它们的文件后缀是合理的。我经常使用类似于以下Rake任务的东西:

  5. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  6. Python 相当于 Perl/Ruby ||= - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。

  7. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  8. ruby-on-rails - 事件管理员日期过滤器日期格式自定义 - 2

    是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s

  9. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  10. python - 如何读取 MIDI 文件、更改其乐器并将其写回? - 2

    我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的

随机推荐