自学内容网 自学内容网

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

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

先看演示视频

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


前言

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


一、爬取思路

1. 主要流程

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

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

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

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

说明:

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

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

2. 代码实现思路

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

二、功能分析

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的文件路径

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. 总结

  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 详情页网络请求

# 用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文件夹!!!

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

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


原文地址:https://blog.csdn.net/wds326598/article/details/143681777

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!