(不看后悔系列二)python网络爬虫爬取网络视频
提示:接上篇文章
记录时间: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个部分去实现:
说明:
- 输入某个演员的名字,检索出她所有的作品,进行分页爬取所有的作品链接,标题等
- 对爬取所有作品的链接进行分析找到m3u8文件,并且下载保存到本地
- 因为保存到本地是保存成ts文件,所以需要将ts文件进行格式转换
文章主要介绍第二部分,也是核心的部分。
2. 代码实现思路
二、功能分析
1. 视频网站分析,寻找m3u8文件
打开无痕浏览器,输入视频播放的网址(暂时不能公开), 打开调试工具。按照上一篇文章中的说明直接搜索关键字m3u8,如图:
- 通过分析我们可以确定2个有用的目标文件,playlist.m3u8 和 video.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的文件路径
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文件的完整域名
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. 总结
- 请求详情页链接获取响应数据
- 解析提取数据获取秘钥以及域名
- 通过域名+秘钥+plistlist.m3u8获取plistlist.m3u8的链接
- 通过访问plistlist.m3u8的链接得到里面的清晰度
- 通过2获取的域名和4获取的清晰度拼接video.m3u8路径
- 获取到video.m3u8路径后,通过网络请求获取里面的video0.jpeg
- 最后拼接2的域名和4的清晰度和6的video.jpeg获取播放片段的链接
- 循环video.m3u8文件内容,拼接video0.jpeg,网络访问
- 保存到本地,文件名字为.ts文件(直接保存成.mp4文件是不能播放的)
注意: 看着这么一大坨,其实分析出来很快的。几分钟的事
三、代码实现
1. 代码框架搭建
创建一个视频下载的类,在里面我们需要写清楚自己要做的事情,如图:
2. 创建网络请求类
这里要重点说明下,网络请求类不能用requests模块请求,因为这些网站都是用的cloudflare服务器,俗称5秒盾,这种服务器自带防爬功能,大家可以自行百度一下爬虫如何绕过5秒盾‘
2.1 详情页网络请求
# 用cloudscraper请求,绕过5妙盾
import cloudscraper
# 注意此方法要写到DownliadVideo类里面,这里只是为了方便粘贴代码
def request_url(self, url):
try:
scraper = cloudscraper.create_scraper()
response = scraper.get(url)
return response
except Exception as e:
# 再次尝试请求
try:
scraper = cloudscraper.create_scraper()
response = scraper.get(url)
return response
except Exception as e:
print(f'{self.title}{url}请求数据失败!!!!')
return
2.2 数据解析提取
# 导入正则模块
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_url
self.main_url = http_url + token_string + '/'
print('主域名', self.main_url)
return self.main_url
else:
print('数据请求失败!!!!')
return None
else:
print(f'第一步请求失败,没有获取到response{response}')
3. 获取质量最高最清晰的视频路径
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_m3u8
else:
print('playlist.m3u8文件请求失败!')
return
4. 请求video.m3u8文件链接获取ts文件,以及保存视频
# 这是下载视频的核心代码!!!!
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文件夹!!!
有需要完整代码的关注点赞私聊~~
还有一段话分享给大家,代码很简单,主要是分析过程,如果分析过程学会了,哪怕在来几个网站都不在话下!