参考资料:

# 配置环境

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视频的更多相关文章

  1. python爬虫脚本下载YouTube视频

    python爬虫脚本下载YouTube视频 爬虫 python YouTube视频 工作环境: python 2.7.13 pip lxml, 安装 pip install lxml,主要用xpath ...

  2. 下载m3u8视频

    分两种情况 同时支持m3u8和mp4文件 某些视频同时支持m3u8和mp4视频文件,将m3u8改成mp4后直接: wget -c http://www.xxx.com/xxxx.mp4 只有m3u8视 ...

  3. python 下载bilibili视频

    说明: 1.清晰度的选择要登录,暂时还没做,目前下载的视频清晰度都是默认的480P 2.进度条仿linux的,参考了一些博客修改了下,侵删 3.其他评论,弹幕之类的相关爬虫代码放在了https://g ...

  4. 爬虫爬取m3u8视频文件

    一.m3u8视频格式 一般m3u8文件和 视频流ts文件放在同一目录 而m3u8文件格式存放的一般都是ts 文件的一个列表 二.根据m3u8视频存放以及写法的规律 思路 我们一般网站上能找到的m3u8 ...

  5. python代码下载m3u8视频

    代码如下: # -*- coding: utf-8 -*- import requests import re import os import base64 from Crypto.Cipher i ...

  6. python下载youtube视频

    谷歌开源了一个新的数据集,BoundingBox,(网址在这里)这个数据集是经过人工标注的视频数据集,自然想将它尽快地运用在实际之中,那么首先需要将其下载下来:可以看到网址上给出的是csv文件,该文件 ...

  7. python下载网页视频

    因网站不同需要修改. 下载 mp4 连接 from bs4 import BeautifulSoup import requests import urllib import re import js ...

  8. (Python基础教程之二十二)爬虫下载网页视频(video blob)

    Python基础教程 在SublimeEditor中配置Python环境 Python代码中添加注释 Python中的变量的使用 Python中的数据类型 Python中的关键字 Python字符串操 ...

  9. Python 爬虫实例(13) 下载 m3u8 格式视频

    Python  requests  下载  m3u8 格式    视频 最近爬取一个视频网站,遇到  m3u8 格式的视频需要下载. 抓包分析,视频文件是多个  ts 文件,什么是 ts文件,请去百度 ...

随机推荐

  1. 一些JavaScript中原理的简单实现

    实现一个双向数据绑定 Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象.通过这个属性可以实现简单的双向数据绑定,当前版 ...

  2. 用缓冲技术OSCache 提高JSP应用的性能和稳定性

    一.概述 在Web应用中,有些报表的生成可能需要数据库花很长时间才能计算出来:有的网站提供天气信息,它需要访问远程服务器进行SOAP调用才能得到温度信息.所有这一切都属于复杂信息的例子.在Web页面中 ...

  3. Win10下JDK环境搭建的两种方法

    jdk1.8--64位官网下载的百度网盘 https://pan.baidu.com/s/1A7jYfupwMWZawb5z_RSdJg 提取码:    92eu 第一种方法(建议)    变量名:  ...

  4. 【转载】[基础知识]【网络编程】TCP/IP

    转自http://mc.dfrobot.com.cn/forum.php?mod=viewthread&tid=27043 [基础知识][网络编程]TCP/IP iooops  胖友们楼主我又 ...

  5. OSX安装Mysql8.0

    OSX下MySQL的安装非常方便,可以通过官网的dmg包进行安装,也可通过brew进行安装.以下介绍如何通过brew如何安装MySQL. 0X00.安装前的准备 既然要通过brew安装,那么就需要确保 ...

  6. kafka Py客户端

    1.pip install kafka-python 2.Producer.py from kafka import KafkaProducer producer = KafkaProducer(bo ...

  7. 听起来很美,用起来很累!停车类APP软肋在哪

    据数据显示,全国现有汽车已达1亿7千万辆,停车位缺于6800万个.而在北京,汽车保有量和车位的配比大约是1:0.5,而国际上一般是1:1.2,结构严重失衡.正所谓哪里有需求,哪里就有市场.停车位的走俏 ...

  8. 通过IE私有滤镜让IE6 7 8支持背景透明,内容不透明效果。

    CSS3已经支持背景rgba的rgba透明度,这一方法可以避免元素内容也随背景一起变透明(详情请阅http://www.cssha.com/css3-new-knowledge-student).但是 ...

  9. 恭喜你,Get到一份 正则表达式 食用指南

    先赞后看,养成习惯 前言 正则表达式 正则表达式: 定义一个搜索模式的字符串. 正则表达式可以用于搜索.编辑和操作文本. 正则对文本的分析或修改过程为:首先正则表达式应用的是文本字符串(text/st ...

  10. shell编程1:变量的使用与例子

    一.Shell脚本的执行通常可以采用以下几种方式: 1):bash script-name或sh script-name(推荐使用) 2):path/script-name 或./script-nam ...