爬虫 | Python下载m3u8视频
参考资料:
# 配置环境
import requests,re
import sys,time
import os
import numpy as np
import glob
work_dir = os.getcwd()
print(work_dir)
# 用来保存ts文件
file_dir = os.path.join(work_dir,'file_tmp')
if not os.path.exists(file_dir):
os.mkdir(file_dir)
先定义保存文件的函数
def savefile(file_url,file_name):
# 配置headers防止被墙,一般问题不大
headers = {
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36'
}
r = requests.get(file_url,headers=headers)
if r.status_code == 200:
with open(file_name, 'wb') as f:
f.write(r.content)
从 m3u8 文件中解析出 ts 信息
怎么查找m3u8文件?
假设在chrome上打开视频页
右键检查,Network -> All ,过滤.m3u8
一般可以看到两个m3u8地址,其中一个是带hls
的,这个文件可以解析出ts信息
拿个网址来举例,比如这个视频
# 如果url中没有hls的,那就是源m3u8文件
# 源m3u8文件会跳转到另一个m3u8文件,这个地址中就带有hls
# 这个是源m3u8文件,不带hls
url_m3u8 = 'https://wuji.zhulong-zuida.com/20190706/762_c260ca6c/index.m3u8'
r = requests.get(url_m3u8)
r.encoding='utf-8'
# 查看内容
print(r.text)
输出:
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=800000,RESOLUTION=1080x608
800k/hls/index.m3u8
可以看到最后一行就是跳转后的m3u8地址
# 合成带有hls的m3u8地址
if r.text.split('\n')[-1] == '':
hls_mark = r.text.split('\n')[-2] # 以防\n结尾
else:
hls_mark = r.text.split('\n')[-1]
url_m3u8_hls = url_m3u8.replace('index.m3u8',hls_mark)
url_m3u8_hls
输出:
'https://wuji.zhulong-zuida.com/20190706/762_c260ca6c/800k/hls/index.m3u8'
# 不过有时候可能没法查到跳转后的带hls的连接
# 但是视频加载文件的网址格式为 主url+文件名.ts
# 这个主url是带hls的
# m3u8的index目录 格式为 主url/index.m3u8
url_m3u8_hls = 'https://wuji.zhulong-zuida.com/20190706/762_c260ca6c/800k/hls/index.m3u8'
# 带有hls的m3u8文件中获得的是ts信息
# 包括ts文件名称,以及该文件的持续时间
# 这个文件有用,先保存一下
file_m3u8 = url_m3u8_hls.split('/')[-1]
with open(file_m3u8,'wb') as f:
f.write(r.content)
# iter_lines得到的是bytesstring
text_bytes = list(r.iter_lines())
# 转化成正常string
text_string = [i.decode('utf-8') for i in text_bytes]
# 筛选以.ts结尾的行
# 有些情况下可能是以其他格式的文件,比如png,下载后修改后缀即可
# ts_name = [i for i in text_string if i.endswith('.ts')]
ts_name = [i for i in text_string if not i.startswith('#')]
ts_name[:3]
输出:
['36962c1a1b0000000.ts', '36962c1a1b0000001.ts', '36962c1a1b0000002.ts']
有时候ts文件信息中可能还包含一部分路径信息。
因为路径都是统一的,所以我们只需要文件名就可以了
if '/' in ts_name[1]:
# 部分ts文件名中带有路径信息,只保留文件名即可
ts_name = [i.split('/')[-1] for i in ts_name]
ts_name[:3]
接下来处理时间戳。
# 筛选带有时间的行
ts_time = [float(re.findall('[.\d]+',i)[0]) for i in text_string if i.startswith('#EXTINF')]
ts_time[:3]
输出:
[4.1283, 4.3785, 4.17]
# 检验解析出来的时间戳和文件名数量是否匹配
len(ts_name) == len(ts_time)
输出:
True
按时间截取视频
# 建立时间基准
# 得到累计时间序列
time_cum = np.cumsum(ts_time)
# 那如果我要看51分05秒~55分46秒,应该下载哪些文件呢?
time_start = 1*3600+26*60+5
time_end = 1*3600+46*60+20
# 如果有多段时间截取,可以写个函数将时间序列进行转化
# 输入:[(0.0.0,0.9.30),(0.10.0,0.20.0)]
# 输出 累计时间戳的index [(0,38),(40,80)]
# 对于起始时间
# 筛选累计时间戳<开始时间的最大值,再找对应的index
index_start = sum(time_cum<time_start)+1-1
# +1是为了截取
# -1 是为了矫正index序号
这个就是最终的index,我们这里的原则是最后取到的时间区间是完全包含目标区间的
这里的index实际上做了一个位移的,本来index是0开始,所以说是351
e.g. 假设前3个ts的时间为2,3,3
现在我要的是第4秒后的信息,得到的累计时间序列是2,5,8
按照我们刚才的那个判断,<4的只有1个时间位,但从自然顺序上我们是要从第二个ts文件开始截取
这就相当于index不用再变动了,如果其他软件序列语法是1开始的话,那么这个index
# 对于截止时间
index_end = len(time_cum) - sum(time_cum>time_end) +1 - 1
同样假设 整个累计时间序列为 2,5,8,10
现在截取到6秒,所以要取到第3个ts文件(Python index为2)
时间序列长度4-大于6的个数2+偏移1位-index矫正1位
这就是最终的index
print(index_start,index_end)
输出:
1290 1594
抓取 ts 文件
单文件测试
ts_name[0] # 这个是片头
输出:
'36962c1a1b0000000.ts'
# 这个网址去除掉最后的文件名就是**主url**了。
file_url = 'https://wuji.zhulong-zuida.com/20190706/762_c260ca6c/800k/hls/36962c1a1b0000000.ts'
# 提取文件名
file_name = os.path.join(file_dir,file_url.split('/')[-1])
# 下载ts文件到本地
savefile(file_url,file_name)
批量下载
# 先看下我们要抓取的ts文件的index的起始位置
print(index_start,index_end)
输出:
1290 1594
# ts文件的主url以/hls/结束
url_m3u8_hls
输出:
'https://wuji.zhulong-zuida.com/20190706/762_c260ca6c/800k/hls/index.m3u8'
# 提取主url
url_ts_main = url_m3u8_hls.replace('index.m3u8','')
# 绝大部分hls文件的名称都是index.m3u8,个别的也可能是其他名字
# range 函数取头不取尾,所以+1
for idx in range(index_start,index_end+1):
# 拼接url
file_name = ts_name[idx]
file_url = url_ts_main+file_name
# 对于后缀可能是其他格式的情况下,保存为以.ts结尾的文件即可
# 有的服务器可能会改变后缀假装自己不是ts文件
if not file_name.endswith('ts'):
tmp_name = file_name.split('.')[:-1]
tmp_name.append('ts')
file_name = '.'.join(tmp_name)
file_path = os.path.join(file_dir,file_name)
# 保存文件
savefile(file_url,file_path)
# 提示进度
sys.stdout.write('\r当前进度 第%d页 剩余%d页'%(idx,index_end-idx))
sys.stdout.flush()
time.sleep(0.1)
输出:
当前进度 第1594页 剩余0页
合并 ts 文件
第一种方式可以考虑,使用命令行操作
如果是在windows上操作
copy /b 路径\*.ts 路径\合并文件.ts
copy /b “1.ts”+“2.ts”+…+”n.ts” /y “combine.ts”
如果是在mac上操作
cat 1.ts 2.ts > combine.ts
注意:文件的顺序要正确才行
# 如果有ts文件的index
# 那么可以用index直接来生成有顺序的list即可
file_list = [os.path.join(file_dir,ts_name[i]) \
for i in range(index_start,index_end+1)]
# 直接扫描路径下的ts文件也是可以的
# 也可以删掉部分ts文件
# file_list = glob.glob(os.path.join(file_dir,'*.ts'))
# file_list.sort()
# 这里是在mac上操作,所以名称以空格相连
filepath_cat = ' '.join(file_list)
cmd_str = 'cat ' + filepath_cat + '> merge.ts'
# cat 1.ts 2.ts > combine.ts
os.system(cmd_str)
执行成功的话,会返回0
第二种合并ts文件的方式,可以将所有的ts文件按顺序写到一个新的文件中。
file_out = 'merge_02.ts'
with open(file_out,'wb') as f_out:
for f_in in file_list:
f_out.write(open(f_in,'rb').read())
将合并的ts文件转化为视频文件
最后,我们将合成的ts文件转化成视频文件(比如MP4格式)
这里我们调用 ffmpeg 将 ts 文件转化为视频文件。
转化命令为
ffmpeg -i 文件名称.ts -c copy [视频名称]
- e.g.
ffmpeg -i merge.ts -c copy '视频截取片段.mp4'
file_in = os.path.join(work_dir,'merge.ts')
#如果路径中有空格,所以路径需要用上双引号,否则会找不到该文件
file_out = "merge.mp4"
# 这里是去ffmpeg官网下载编译好的软件包,免安装的
cmd = './ffmpeg -i '+file_in +' -c copy ' + file_out
os.system(cmd) # 运行正常返回0
爬虫 | Python下载m3u8视频的更多相关文章
- python爬虫脚本下载YouTube视频
python爬虫脚本下载YouTube视频 爬虫 python YouTube视频 工作环境: python 2.7.13 pip lxml, 安装 pip install lxml,主要用xpath ...
- 下载m3u8视频
分两种情况 同时支持m3u8和mp4文件 某些视频同时支持m3u8和mp4视频文件,将m3u8改成mp4后直接: wget -c http://www.xxx.com/xxxx.mp4 只有m3u8视 ...
- python 下载bilibili视频
说明: 1.清晰度的选择要登录,暂时还没做,目前下载的视频清晰度都是默认的480P 2.进度条仿linux的,参考了一些博客修改了下,侵删 3.其他评论,弹幕之类的相关爬虫代码放在了https://g ...
- 爬虫爬取m3u8视频文件
一.m3u8视频格式 一般m3u8文件和 视频流ts文件放在同一目录 而m3u8文件格式存放的一般都是ts 文件的一个列表 二.根据m3u8视频存放以及写法的规律 思路 我们一般网站上能找到的m3u8 ...
- python代码下载m3u8视频
代码如下: # -*- coding: utf-8 -*- import requests import re import os import base64 from Crypto.Cipher i ...
- python下载youtube视频
谷歌开源了一个新的数据集,BoundingBox,(网址在这里)这个数据集是经过人工标注的视频数据集,自然想将它尽快地运用在实际之中,那么首先需要将其下载下来:可以看到网址上给出的是csv文件,该文件 ...
- python下载网页视频
因网站不同需要修改. 下载 mp4 连接 from bs4 import BeautifulSoup import requests import urllib import re import js ...
- (Python基础教程之二十二)爬虫下载网页视频(video blob)
Python基础教程 在SublimeEditor中配置Python环境 Python代码中添加注释 Python中的变量的使用 Python中的数据类型 Python中的关键字 Python字符串操 ...
- Python 爬虫实例(13) 下载 m3u8 格式视频
Python requests 下载 m3u8 格式 视频 最近爬取一个视频网站,遇到 m3u8 格式的视频需要下载. 抓包分析,视频文件是多个 ts 文件,什么是 ts文件,请去百度 ...
随机推荐
- MariaDB 命令
1.账号登入 mysql -u root -p 上述命令,“root” 是登入账号,上述命令回车后,则进行密码的输入 登入成功后如下: 2.创建用户命令 create user 'new_user'@ ...
- js 实现排序算法 -- 希尔排序(Shell Sort)
原文: 十大经典排序算法(动图演示) 希尔排序 1959年Shell发明,第一个突破O(n2)的排序算法,是简单插入排序的改进版.它与插入排序的不同之处在于,它会优先比较距离较远的元素.希尔排序又叫缩 ...
- Css兼容性大全
知识有所欠缺 疯狂脑补抄袭经验中... 兼容性处理要点1.DOCTYPE 影响 CSS 处理 2.FF: 设置 padding 后, div 会增加 height 和 width, 但 IE 不会, ...
- Leetcode 946. Validate Stack Sequences 验证栈序列
946. Validate Stack Sequences 题目描述 Given two sequences pushed and popped with distinct values, retur ...
- Python---4字符串与编码
字符编码 字符串比较特殊的是还有一个编码问题. 因为计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理.最早的计算机在设计时采用8个比特(bit)作为一个字节(byte),所以,一个 ...
- 查漏补缺:Vector中去重
对于STL去重,可以使用<algorithm>中提供的unique()函数. unique()函数用于去除相邻元素中的重复元素(所以去重前需要对vector进行排序),只留下一个.返回去重 ...
- python设置检查点简单实现
说检查点,其实就是对过去历史的记录,可以认为是log.不过这里进行了简化.举例来说,我现在又一段文本.文本里放有一堆堆的链接地址.我现在的任务是下载那些地址中的内容.另外因为网络的问题或者网站的问题, ...
- Golang: chan定义问题(7)
通常都是定义读写双向的 chan,定义单向 chan 问题. 专栏的介绍可以参考 <GotchaGolang专栏>,代码可以看<宝库-Gotcha>. 通过 只写 chan 传 ...
- C2C的道德边界:沦为从假运单到假病条的供假渠道
你可能刚开始学会不去看网购平台上商品回评中的虚假好评,却又要开始应对同事在朋友圈等平台买来的虚开病假条带来的困扰.最近各大媒体包括党报热传的网购病假条事件,再度将人们的目光集中在这个C2C模式之上.从 ...
- 硬件小白学习之路(1)稳压芯片LM431
图稳压芯片LM431简介 偶然的机会接触到LM431这个芯片,周末晚上打发无聊的时光,查资料进行剖析. LM431的Symbol Diagram和Functional Diagram如图1所示,下面分 ...