使用爬虫爬取热门电影

文章目录

      • 网站存储视频的原理
      • M3U8文件解读
      • 网站分析
      • 代码实现

网站存储视频的原理

首先我们来了解一下网站存储视频的原理。

一般情况下,一个网页里想要显示出一个视频资源,必须有一个<video>标签,

<video src="xxx.mp4"></video>

这个video标签里面的src并不是视频的真正下载地址,几乎没有视频网站会在video里直接给出下载地址。

因为这种方案使得用户体验极差,既占网速又占内存。

更好的方案是对视频进行切片(ts),切完了以后每个切片都有一个独立的url,当我们把所有的切片都获取到以后,再把切片文件的正确顺序进行保存,然后合并就可以得到一个完整的视频。

既然要把视频切成非常多个小碎片. 那就需要有个文件来记录这些小碎片的路径. 该文件一般为M3U文件. M3U文件中的内容经过UTF-8的编码后, 就是M3U8文件. 今天, 我们看到的各大视频网站平台使用的几乎都是M3U8文件.

现在的视频网站用的几乎都是这种方案。正确的加载方案是

  1. 先请求到M3U8文件
  2. 加载切片(ts)文件
  3. 正常播放视频

这样做的好处是可以节省网络资源,当用户快进的时候,服务器可以直接定位到对应的ts文件进行加载,极大提升用户体验,可以减小服务器压力。

M3U8文件解读

随便点击一个电影

在这里插入图片描述

F12抓包,可以看到里面有m3u8文件和ts切片文件。

M3U8内容如下:

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=128,RESOLUTION=1142x480
900k_0X480_64k_25/hls/index.m3u8

所有的带#号的都是字段名称,不带#号的一般是路径或者文件名称。

900k_0X480_64k_25/hls/index.m3u8

很明显这里是一个网页的路径,对应一个新的M3U8文件

在这里插入图片描述

那么我们找到下面的M3U8文件,对比一下路径

https://pptv.1080tg.com/202312/21/BxEB9XJSw23/video/900k_0X480_64k_25/hls/index.m3u8

发现第一个M3U8文件里的路径就是第二个M3U8文件的URL。

第二个M3U8文件才是真实的视频的路径,内容如下:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:4
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:3.560000,
https://pptv.shanshanku.com/202312/21/BxEB9XJSw23/video/900k_0X480_64k_25/hls/player0000.ts
#EXTINF:2.000000,
https://pptv.shanshanku.com/202312/21/BxEB9XJSw23/video/900k_0X480_64k_25/hls/player0001.ts
#EXTINF:1.520000,
https://pptv.shanshanku.com/202312/21/BxEB9XJSw23/video/900k_0X480_64k_25/hls/player0002.ts
#EXTINF:2.000000,
https://pptv.shanshanku.com/202312/21/BxEB9XJSw23/video/900k_0X480_64k_25/hls/player0003.ts
......
#EXT-X-ENDLIST

里面最重要的就是每一个ts文件的路径了,而且这个ts文件是没有加密的。

网站分析

接着我们来看一下整个过程,首先我们需要先通过这个网站把m3u8文件获取到。

在这里插入图片描述

直接搜一下网页的源代码,发现m3u8文件的链接就在这个url的字段里面。

我们拿到这个文件就可以去获取第二个m3u8文件,接着再取解析m3u8文件,然后爬取电影切片数据。

步骤如下:

  1. 通过网页源码获取第一层m3u8文件地址
  2. 下载第一层m3u8文件,获取第二层m3u8文件地址
  3. 解析第二层m3u8文件,爬取视频切片
  4. 对TS文件进行合并,还原回MP4文件

代码实现

第一步,我们需要从网页源码中,通过数据解析的方式,拿到第一层m3u8的链接

def GetFirstM3u8Url():# 拿到页面源码url = "https://www.yunbtv.org/vodplay/sandadui-2-1.html"resp= requests.get(url)resp.encoding="utf-8"tree=etree.HTML(resp.text)# 解析出urlscript_content=tree.xpath('//script[contains(text(), "player_aaaa")]/text()')[0]# 我们需要从脚本中提取JSON部分json_str = script_content[script_content.find('{'):script_content.rfind('}') + 1]# 解析JSON字符串data = json.loads(json_str)# 提取URL值url_value = data.get("url", "")print(url_value)

输出结果如下:

在这里插入图片描述

这样的话第一步就完成了。

第一层M3U8的链接拿到之后,接下来需要下载到第二层的M3U8文件

def DownloadM3u8File(first_m3u8_url):resp = requests.get(first_m3u8_url)resp.encoding = "utf-8"url2  = resp.text.split()[-1]# 移除第一个URL的最后一个分段(即去掉'/index.m3u8')base_url = first_m3u8_url.rsplit('/', 1)[0]# 第二层M3U8的地址Second_m3U8_Url = f"{base_url}/{url2}"#下载M3U8文件M3u8Resp=requests.get(Second_m3U8_Url)M3u8Resp.encoding = "utf-8"with open("m3u8.txt",mode="w",encoding="utf-8") as f:f.write(M3u8Resp.text)

实际效果:

在这里插入图片描述

现在我们的m3u8文件就已经下载下来了

接下来处理这个M3U8文件,用协程逐个下载ts文件


# 下载单个ts文件
async def download_one(url):print("正在下载:"+url)# 重试10次 防止下载失败for i in range(10):try:file_name=url.split("/")[-1]async with aiohttp.ClientSession() as session:async with session.get(url) as resp:content=await  resp.content.read()async with aiofiles.open(f"./TsFiles/{file_name}",mode="wb") as f:await f.write(content)breakexcept:print("下载失败:"+url)await asyncio.sleep((i+1)*5)async def download_all_ts():# 准备好任务列表tasks=[]# 读取m3u8文件with open("m3u8.txt",mode="r",encoding="utf-8") as f:for line in f:# 排除所有#开头的if line.startswith("#"):continueline=line.strip()task=asyncio.create_task(download_one(line))tasks.append(task)# 等待任务全部结束await asyncio.wait(tasks)

这样的话,我们的ts文件就下载完成了

在这里插入图片描述

接着通过TS的文件名,进行合并

def MergeTsFiles():print("正在合并文件")name_list=[]with open("m3u8.txt",mode="r",encoding="utf-8") as f:for line in f:# 排除所有#开头的if line.startswith("#"):continueline=line.strip()file_name=line.split("/")[-1]name_list.append(file_name)with open(".\TsFiles\m3u8.txt", mode="w", encoding="utf-8") as f:for data in name_list:f.write("file "+"'"+data+"'"+"\n")# 记录当前的工作目录now_dir = os.getcwd()# 切换工作目录os.chdir("./TsFiles")os.system("D:\\ffmpeg\\ffmpeg.exe -f concat -safe 0 -i m3u8.txt -c copy output.mp4")# 所有操作后要把工作目录切换回来os.chdir(now_dir)print("文件合并完成")

这样的话,所有工作就完成了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/599390.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Note: A Journey Across Canada

A Journey Across Canada 一场横穿加拿大的旅行 across journey After a quiz last autumn, Kuang crossed the continent eastward to Toronto to visit his schoolmate, the distance measuring approximately 5000 kilometers. 去年秋天一次考试后&#xff0c;Kuang向东穿…

数字人克隆系统开发公司?

广州硅基技术开发限公司是一家位于中国广东省广州市的科技公司。该公司专注于人工智能&#xff08;AI&#xff09;领域的研发和创新。广州硅基以技术创新和解决方案为核心&#xff0c;致力于为客户提供高质量的人工智能产品和服务。 广州硅基技术的主要业务包括但不限于&#…

stm32学习笔记:TIIM-输入捕获

输入捕获理论 4个输入捕获和输出比较通道&#xff0c;共用4个CCR寄存器 另外它们的CH1到CH4&#xff0c;4个通道的引脚&#xff0c;也是共用的。 所以对于同一个定时器&#xff0c;输入捕获和输出比较只能使用其中一个&#xff0c;不能同时使用。 电平跳变&#xff1a;上升沿…

《动手学深度学习》学习笔记 第5章 深度学习计算

本系列为《动手学深度学习》学习笔记 书籍链接&#xff1a;动手学深度学习 笔记是从第四章开始&#xff0c;前面三章为基础知道&#xff0c;有需要的可以自己去看看 关于本系列笔记&#xff1a; 书里为了让读者更好的理解&#xff0c;有大篇幅的描述性的文字&#xff0c;内容很…

Spring学习 Spring概述

1.1.Spring介绍 ​ Spring是轻量级Java EE应用开源框架&#xff08;官网&#xff1a; http://spring.io/ &#xff09;&#xff0c;它由Rod Johnson创为了解决企业级编程开发的复杂性而创建 1.2.简化应用开发体现在哪些方面&#xff1f; IOC 解决传统Web开发中硬编码所造成的…

python中collections.abc.Mapping 和collections.Mapping的区别

文章目录 在 Python 中&#xff0c;collections.abc.Mapping 和 collections.Mapping 都是用于表示映射类型&#xff08;即键值对的集合&#xff0c;例如字典&#xff09;的抽象基类。它们的区别在于它们的来源和使用方式。 collections.abc.Mapping 是 collections.abc 模块中…

1月5日代码随想录完全二叉树的节点个数

222.完全二叉树的节点个数 给你一棵 完全二叉树 的根节点 root &#xff0c;求出该树的节点个数。 完全二叉树 的定义如下&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能没填满外&#xff0c;其余每层节点数都达到最大值&#xff0c;并且最下面一层的节点都集中在…

即时设计:轻松实现设计稿动画,打造独具魅力的GIF作品

制作动画 随着动画设计越来越受欢迎&#xff0c;设计师们需要一款强大的工具&#xff0c;以便轻松控制设计稿元素的属性&#xff0c;实现动画效果。今天&#xff0c;我们向您推荐一款具备帧动画功能的设计工具&#xff0c;它可以让您轻松调整元素的宽高、相对位置等属性&#x…

Spring AI 指南

近年来&#xff0c;人工智能技术的迅猛发展改变了我们对科技的看法&#xff0c;并在各个领域引发了巨大的变革。每个人都希望在自己的项目上能够使用人工智能。Spring 框架提供了一个名为 “Spring AI” 的项目&#xff0c;Spring AI 项目旨在简化包含人工智能功能的应用程序的…

Matlab绘制动态心形线

1. 代码 for alpha0:0.1:30 x-1.8:0.001:1.8; y(x.^2).^(1/3)0.9*(3.3-x.^2).^(1/2).*sin(alpha*pi*x); plot(x,y,r-,LineWidth,1.2); set(gca,YGrid,on); axis([-3,3,-2,4]); text(-2,3.35,$f(x)x^{\frac{2}{3}}0.9(3.3-x^2)^{\frac{1}{2}}sin(\alpha\pi x)$,Interpreter,lat…

Geotrust DV通配符证书保护域名数量

Geotrust是一家知名的SSL证书提供商&#xff0c;旗下有多种类型的SSL数字证书&#xff0c;保护网站数据在传输过程中的安全性和完整性&#xff0c;帮助用户确认其网站的安全。通配符SSL证书是Geotrust颁发的一种可以同时保护多个域名站点的SSL证书。今天就随SSL盾小编了解Geotr…

Toshiba 数字隔离器助力工业应用实现稳定的高速隔离数据传输

隔离器件是将输入信号进行转换并输出&#xff0c;以实现输入、输出两端电气隔离的一种安规器件。电气隔离能够保证强电电路和弱电电路之间信号传输的安全性&#xff0c;如果没有进行电气隔离&#xff0c;一旦发生故障&#xff0c;强电电路的电流将直接流到弱电电路&#xff0c;…

啊哈c语言——逻辑挑战8:验证哥德巴赫猜想

上面这封书信是普鲁士数学家哥德巴赫在1742年6月7日写给瑞士数学家欧拉的&#xff0c;哥德巴赫在书信中提出了“任一大于2的整数都可以写成3个质数之和”的猜想。当时&#xff0c;哥德巴赫遵照的是“1也是素数”的约定。现今&#xff0c;数学界已经不使用这个约定了。哥德巴赫原…

Spring Boot 整合 Knife4j(快速上手)

关于 Knife4j 官方文档&#xff1a;https://doc.xiaominfo.com/ Knife4j是一个基于Swagger的API文档生成工具&#xff0c;它提供了一种方便的方式来为Spring Boot项目生成在线API文档。Knife4j的特点包括&#xff1a; 自动化生成&#xff1a;通过Swagger注解&#xff0c;Kn…

凸优化 3:最优化方法

凸优化 3&#xff1a;最优化方法 最优化方法适用场景对比费马引理一阶优化算法梯度下降最速下降 二阶优化算法牛顿法Hessian矩阵Hessian矩阵的逆Hessian矩阵和梯度的区别牛顿法和梯度下降法的区别 拟牛顿法DFP、BFGS/L-BFGS 数值优化算法坐标下降法SMO算法 基于导数的函数优化解…

FCN学习-----第一课

语义分割中的全卷积网络 CVPR IEEE国际计算机视觉与模式识别会议 PAMI IEEE模式分析与机器智能汇刊 需要会的知识点&#xff1a; 神经网络&#xff1a;前向传播和反向传播 卷积神经网络&#xff1a;CNN&#xff0c;卷积&#xff0c;池化&#xff0c;上采样 分类网络&#xff1a…

杨中科 ASP.NETCore Rest

什么是Rest RPC 1、Web API两种风格: 面向过程(RPC) 、面向REST (REST) 2、RPC:“控制器/操作方法“的形式把服务器端的代码当成方法去调用。把HTTP当成传输数据的通道&#xff0c;不关心HTTP谓词。通过QueryString请求报文体给服务器传递数据。状态码。比如/Persons/GetAll…

【LeetCode】608. 树节点

表&#xff1a;Tree ------------------- | Column Name | Type | ------------------- | id | int | | p_id | int | ------------------- id 是该表中具有唯一值的列。 该表的每行包含树中节点的 id 及其父节点的 id 信息。 给定的结构总是一个有效的树。…

stm32学习笔记:TIM-输出比较

四部分讲解内容&#xff0c;本文是第二部分 输出比较主要用于PWM波形的控制电机&#xff08;驱动电机的必要条件&#xff09; 1、定时器基本定时&#xff0c;定一个时间&#xff0c;然后让定时器每隔一段时间产生一个中断&#xff0c;来实现每隔一个固定时间执行一段程序的目…

linux磁盘管理实验1

1.在安装好的linux系统中新加一块硬盘&#xff0c;将硬盘分成2个主分区&#xff0c;和2个逻辑分区&#xff0c;将其中一个逻辑分区设置成vfat&#xff08;FAT32&#xff09;分区&#xff0c;并实现开机自动挂载所有分区。 答&#xff1a;添加一个硬盘为sdb 分成2个主分区&#…