(不看后悔系列二)python网络爬虫爬取网络视频

server/2024/11/18 0:00:48/

提示:接上篇文章
记录时间:2024-11-12,预计代码到2026年均有效。

先看演示视频

再看图片
在这里插入图片描述

文章目录

  • 前言
  • 一、爬取思路
    • 1. 主要流程
    • 2. 代码实现思路
  • 二、功能分析
    • 1. 视频网站分析,寻找m3u8文件
    • 2. playlist.m3u8视频清晰度
    • 3. 寻找秘钥
    • 4. m3u8文件完整地址
    • 5. 播放文件完整地址
    • 6. 总结
  • 三、代码实现
    • 1. 代码框架搭建
    • 2. 创建网络请求类
      • 2.1 详情页网络请求
      • 2.2 数据解析提取
    • 3. 获取质量最高最清晰的视频路径
    • 4. 请求video.m3u8文件链接获取ts文件,以及保存视频
  • 总结


前言

接上篇文章,今天我们来探讨一下承人网站视频如何爬取,并且用代码去实现!!!


一、爬取思路

1. 主要流程

我们首先要明白整体的思路,明确知道我们想要什么,再去爬取视频。这点很重要

例如:我想实现输入某个演员的名字,检索出这个演员的所有电影,并且自动翻页进行下载。

整个流程我们分成3个部分去实现:

1.输入演员名字进行搜索
2.找视频并下载
3.视频格式转换

说明:

  1. 输入某个演员的名字,检索出她所有的作品,进行分页爬取所有的作品链接,标题等
  2. 对爬取所有作品的链接进行分析找到m3u8文件,并且下载保存到本地
  3. 因为保存到本地是保存成ts文件,所以需要将ts文件进行格式转换

文章主要介绍第二部分,也是核心的部分。

2. 代码实现思路

对目标网站发起网络请求
解析返回的数据
找到m3u8文件地址
再次发起网络请求
解析m3u8数据
寻找ts主域名
拼接ts文件对并ts发起网络请求
保存到本地成一个完整的ts
将ts转换成mp4

二、功能分析

m3u8_62">1. 视频网站分析,寻找m3u8文件

打开无痕浏览器,输入视频播放的网址(暂时不能公开), 打开调试工具。按照上一篇文章中的说明直接搜索关键字m3u8,如图:
在这里插入图片描述

  • 通过分析我们可以确定2个有用的目标文件,playlist.m3u8video.m3u8
  • 把这个2个文件链接分别下载出来,看看是什么?如下图:

在这里插入图片描述

在这里插入图片描述

  • 通过查看第一个文件playlist.m3u8内容大概可以猜测到,这是一个清晰度,有640*360,842 * 480,1280 * 720,并且后面还会带着一个路径正好是video.m3u8
  • 我们在来仔细查看第二个文件video.m3u8,你会发现里面都是video0.jpeg, video1.jpeg。我在上篇文章提到过,m3u8文件里面包含的应该是视频小片段即ts文件,而这个里面全是jpeg,哪怕你在浏览器下载也不能用。
  • 其实这是网站管理人员做的防爬工作,迷惑你的。jpeg,你请求的时候,就按照jpeg请求或者直接改成.ts文件即可

到这我们能够确定playlist.m3u8是负责视频清晰度的m3u8,而video.m3u8里面才是真正的视频文件。
也就是说,我们需要先找playlist.m3u8提取视频清晰度,然后把提取清晰度拼接到video.m3u8中,这样才能获取整个video.m3u8的文件路径

m3u8_80">2. playlist.m3u8视频清晰度

我们还看直接最一开始的抓包图片:
在这里插入图片描述

  • 我们会发现,视频清晰度的链接是 https://surrit.com/96f46bb4-9633-40bd-9bba-2299e0f25f5e/playlist.m3u8
  • 可能域名是固定的,但是后面96f46bb4-9633-40bd-9bba-2299e0f25f5e肯定不是固定的,我们需要找到这个token或者说是秘钥,只有找到这个,才能访问到playlist.m3u8文件。

3. 寻找秘钥

最简单的办法,把整个秘钥复制出来,然后放到搜索栏进行搜索,找到以后通过正则表达式提取出来。如图
在这里插入图片描述
确实能够找到,也能提取出来。但是这不准确,有的视频能找到,有的视频没有。当你遇到没有的时候,视频就会下载失败。

正确的搜索是,搜索少部分关键字,96f46bb4,如图:
在这里插入图片描述

  • 我们把搜索出来的这一行代码拿出来,比较多,重要信息我标红

{“indexs”:[0],“value”:[{“id”:18959,“disposeCode”:“DIS241106 eval(function(p,a,c,k,e,d){e=function©{return c.toString(36)};if(!‘’.replace(/^/,String)){while(c–){d[c.toString(a)]=k[c]||c.toString(a)}k=[function(e){return d[e]}];e=function(){return’\w+‘};c=1};while(c–){if(k[c]){p=p.replace(new RegExp(’\b’+e©+‘\b’,‘g’),k[c])}}return p}(‘f=‘8://7.6/5-4-3-2-1/e.0’;d=‘8://7.6/5-4-3-2-1/c/9.0’;b=‘8://7.6/5-4-3-2-1/a/9.0’;’,16,16,m3u8|2299e0f25f5e|9bba|40bd|9633|96f46bb4|com|surrit|https|video|1280x720|source1280|842x480|source842|playlist|source’.split(‘|’),0,{}))200001”,“entrustCode”:“”,“materialCode”:“MTR241106200007”,“materialId”:“MTR241106200007”,“materialName”:“批次得上传结算单”,“quantity”:10,“materialUnit”:“26”,“taxIncludedPrice”:null,“isTax”:1,“taxRate”:3,“images”:“https://file.jupai.net/2024/11/06/uploadtkirw93n4uj7zaon.jpg”,“videoUrl”:null,“materialType”:null,“startPrice”:null,“marketPrice”:null,“bidderAptitudes”:null,“leastApplyCorpNum”:null,“leastBidNum”:null,“isAuction”:1,“remark”:null,“realAddSystemId”:null,“addTime”:null,“matterCode”:“MT241106200007”,“bound”:true}],“values”:[[{“id”:18959,“disposeCode”:“DIS241106200001”,“entrustCode”:“”,“materialCode”:“MTR241106200007”,“materialId”:“MTR241106200007”,“materialName”:“批次得上传结算单”,“quantity”:10,“materialUnit”:“26”,“taxIncludedPrice”:null,“isTax”:1,“taxRate”:3,“images”:“https://file.jupai.net/2024/11/06/uploadtkirw93n4uj7zaon.jpg”,“videoUrl”:null,“materialType”:null,“startPrice”:null,“marketPrice”:null,“bidderAptitudes”:null,“leastApplyCorpNum”:null,“leastBidNum”:null,“isAuction”:1,“remark”:null,“realAddSystemId”:null,“addTime”:null,“matterCode”:“MT241106200007”,“bound”:true}]]}

  • 仔细查看能够看到秘钥token(96f46bb4-9633-40bd-9bba-2299e0f25f5e)也就是标红中(|2299e0f25f5e|9bba|40bd|9633|96f46bb4|)的倒序排列,同时我们也能看出来,标红中还有域名,真是一举两得。
  • 也就是说 我们拿到这些数据,然后通过正则表达式提取可以得到1个域名,1个秘钥,然后拼接就能得到真正的playlist.m3u8文件

那我们就看看这些数据如何得到 ?我们继续查看网站的header请求头
在这里插入图片描述

  • 我们会发现,其实这就是请求的详情页的链接,然后获取的相应数据。

那这就简单了,打开详情页,获取响应数据,解析数据用正则表达式提取秘钥和域名,拼接后可以下载playlist.m3u8。就可以拿到里面的清晰度。找到清晰度以后,在找m3u8文件的完整域名

m3u8_105">4. m3u8文件完整地址

通过上面分析,我们搜出m3u8文件,先查看一下它的链接,如图:
在这里插入图片描述

  • 很巧合video.m3u8完整路径是2部分组成,一部分是域名+秘钥,另一部分是清晰度后缀。这2个我们已经找到了,也就是说video.m3u8文件已经被我们完全找到了。

我们还差一个东西没有找到,就是video.m3u8文件里面包含的仅仅是video0.jpeg,video1.jpeg,video2.jpeg…,并不是全部的域名,我们需要在次找到这个播放的域名,然后和这个video0.jpeg拼接起来才能组成一个完整的播放片段

5. 播放文件完整地址

我们继续搜,让视频播放的时候搜,看看他播放的时候是如何加载video0.jpeg这些文件的。如图:

在这里插入图片描述
我们会发现,他播放视频片段的完整路径可以是由3部分构成域名+清晰度+m3u8的文件内容(vide0.jpeg)
域名我们知道,清晰度也知道, video.jpeg也知道。至此我们分析完毕!

6. 总结

  1. 请求详情页链接获取响应数据
  2. 解析提取数据获取秘钥以及域名
  3. 通过域名+秘钥+plistlist.m3u8获取plistlist.m3u8的链接
  4. 通过访问plistlist.m3u8的链接得到里面的清晰度
  5. 通过2获取的域名和4获取的清晰度拼接video.m3u8路径
  6. 获取到video.m3u8路径后,通过网络请求获取里面的video0.jpeg
  7. 最后拼接2的域名和4的清晰度和6的video.jpeg获取播放片段的链接
  8. 循环video.m3u8文件内容,拼接video0.jpeg,网络访问
  9. 保存到本地,文件名字为.ts文件(直接保存成.mp4文件是不能播放的)

注意: 看着这么一大坨,其实分析出来很快的。几分钟的事

三、代码实现

1. 代码框架搭建

创建一个视频下载的类,在里面我们需要写清楚自己要做的事情,如图:

在这里插入图片描述

2. 创建网络请求类

这里要重点说明下,网络请求类不能用requests模块请求,因为这些网站都是用的cloudflare服务器,俗称5秒盾,这种服务器自带防爬功能,大家可以自行百度一下爬虫如何绕过5秒盾

2.1 详情页网络请求

python"># 用cloudscraper请求,绕过5妙盾
import cloudscraper# 注意此方法要写到DownliadVideo类里面,这里只是为了方便粘贴代码def request_url(self, url):try:scraper = cloudscraper.create_scraper()response = scraper.get(url)return responseexcept Exception as e:# 再次尝试请求try:scraper = cloudscraper.create_scraper()response = scraper.get(url)return responseexcept Exception as e:print(f'{self.title}{url}请求数据失败!!!!')return

2.2 数据解析提取

python"># 导入正则模块
import re# 解析详情页数据获取域名def parse_urls(self, response):if response:if response.status_code == 200:# 获取token(是倒序并且是xxx05|xxx04|xxxx03|xxxx02|xxxx01形式)token = re.findall('m3u8\|(.*?)\|com', response.content.decode())[0]# 通过|分割成数组parts = token.split('|')# 倒序排列(01 02 03)reordered_parts = parts[::-1]# 并且用-连接成(01-02-03)token_string = '-'.join(reordered_parts)# 获取主域名http_str = re.findall('com\|(.*?)\|https', response.content.decode())[0]# 拼接完整的主域名http_url = f'https://{http_str}.com/'# 赋值给全局属性main_urlself.main_url = http_url + token_string + '/'print('主域名', self.main_url)return self.main_urlelse:print('数据请求失败!!!!')return Noneelse:print(f'第一步请求失败,没有获取到response{response}')

3. 获取质量最高最清晰的视频路径

python">    def get_playListm3u8(self, playlist_url):if playlist_url.status_code == 200:# 如果请求成功,用正则提取video.m3u8 pattern = r'([^\n]+\/video\.m3u8)\n'plist_list = re.findall(pattern, playlist_url.content.decode())# 拼接视频m3u8文件,获取完整的路径video_m3u8 = self.main_url + plist_list[-1]# 提取播放视频的url文件self.videos_url = video_m3u8.split('video.m3u8')[0]print('m3u8文件', video_m3u8)return video_m3u8else:print('playlist.m3u8文件请求失败!')return

m3u8ts_217">4. 请求video.m3u8文件链接获取ts文件,以及保存视频

python">	# 这是下载视频的核心代码!!!!def parase_m3u8(self, m3u8):# 获取video.m3u8文件里面的内容ts_list = re.findall(',\n(.*?)\n#', m3u8)# 遍历数组for ts in tqdm(ts_list):# 拼接完整的视频片段路径video_url = self.videos_url + ts# 再次网络请求视频片段路径video_content = self.request_url(video_url)# 保存到本地video的文件夹内with open('./video/' + self.title + '.ts', mode='ab') as f:f.write(video_content.content)print(f'{self.title},下载完成!!!')
  • 上面就是下载视频的核心代码,但其实我们在下载这要考虑因素比较多点,例如,下载失败的情况,或者某一个视频片段加载失败的情况,完整的代码如图:这里就不粘贴了
    在这里插入图片描述

总结

一些核心的视频下载代码就是这些了,但是如果需要一个完整的还需要实现搜索,列表翻页,列表链接标题等重要信息提取等以及ts下载完以后格式转换。

注意:

1. 一定要在科学上网的情况下运行代码!!!
2. 一定要在同级目录下提前创建一个video文件夹!!!

有需要完整代码的关注点赞私聊~~

还有一段话分享给大家,代码很简单,主要是分析过程,如果分析过程学会了,哪怕在来几个网站都不在话下!


http://www.ppmy.cn/server/142758.html

相关文章

【Java Web】Ajax 介绍及 jQuery 实现

文章目录 AJAX介绍XMLHttpRequestjQuery实现Ajax$.ajax()$().load()$.get()$.post() AJAX介绍 AJAX(Asynchronous JavaScript and XML)是一种创建高效、动态网页应用的网页开发技术。它允许在不重新加载整个页面的情况下进行异步数据更新和交互&#xf…

蓝队知识浅谈(上)

声明:学习视频来自b站up主 泷羽sec,如涉及侵权马上删除文章 感谢泷羽sec 团队的教学 视频地址:蓝队基础之网络七层杀伤链_哔哩哔哩_bilibili 本文主要分享一些蓝队相关的知识。 首先我们先来了解一下什么是蓝队? 蓝队是信息安全领…

Docker compose部署Activemq

整个工具的代码都在Gitee或者Github地址内 gitee:solomon-parent: 这个项目主要是总结了工作上遇到的问题以及学习一些框架用于整合例如:rabbitMq、reids、Mqtt、S3协议的文件服务器、mongodb github:GitHub - ZeroNing/solomon-parent: 这个项目主要是…

【书生大模型实战营 闯关材料】入门岛:第4关 玩转HF/魔搭/魔乐社区

2.1.2-2.1.3 InternLM 模型下载 模型下载 使用Hugging Face平台、魔搭社区平台(可选)和魔乐社区平台(可选)下载文档中提到的模型(至少需要下载config.json文件、model.safetensors.index.json文件)&#x…

Spring Boot编程训练系统:开发与管理

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统,它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等,非常…

大三学生实习面试经历(1)

最近听了一位学长的建议,不能等一切都准备好再去开始,于是就开始了简历投递,恰好简历过了某小厂的初筛,开启了线上面试,记录了一些问题: (通过面试也确实了解到了自己在某些方面确实做的还不够…

结构体的简单操作

代码结构 代码&#xff1a; main.c #include <stdio.h> #include <stdlib.h> #include <string.h>//定义结构体 struct Student{char name[10];int score;int age; };//打印结构体信息 void PrintStruct(const struct Student s) {printf("Student.na…

thinkphp 连表查询

在ThinkPHP中&#xff0c;可以使用Query类的join方法来进行连表查询。连表查询可以用于在查询结果中包含多个表的数据&#xff0c;以便获取更丰富的信息。 以下是一个简单的例子&#xff0c;假设有两个表user和order&#xff0c;我们想要查询用户的订单信息&#xff1a; $use…