梨视频怎么保存到电脑(Python爬取视频的几种方法)

首页教程更新时间:2023-06-07 08:12:05

今天和大家分享下我近段时间get的新技能,用单线程、多线程和协程三种方式爬取并下载梨视频的小视频,话不多说,我们开始叭。冲鸭冲鸭!

目标

将梨视频上的科技相关的视频资源下载保存到电脑本地

工具

需要用到的第三方库

1) requests # 发送请求2) parsel # 解析数据(支持re, xpath, css)3) fake_useragent # 构建请求头4) random # 生成随机数5) os # 操作路径/生成文件夹6) json # 处理json数据7) concurrent # 处理线程池8) asyncio, aiohttp, aiofiles # 处理协程

分析并使用单线程下载视频

我们需要将梨视频网站上的视频资源下载到电脑本地,那必不可少的两个元素必然是视频名称视频资源url。获取视频资源url后,针对视频资源的url发起请求,得到响应,再将响应内容以视频名称为名保存到电脑本地即可。

起始页:科技热点资讯短视频_科技热点新闻-梨视频官网-Pear Video

URL地址:https://www.pearvideo.com/category_8

1.分析起始页

F12对起始页刷新抓包,拿到数据请求接口

梨视频怎么保存到电脑,Python爬取视频的几种方法(1)

梨视频(科技)主页

梨视频怎么保存到电脑,Python爬取视频的几种方法(2)

对比观察抓包获取到的url:

https://www.pearvideo.com/category_loading.jsp?reqType=5&categoryId=8&start=12&mrd=0.6312621497255415&filterIds=1745912,1745729,1745750,1745761,1745809,1745640,1745278,1745506,1745193,1606956,1745335,1745147

https://www.pearvideo.com/category_loading.jsp?reqType=5&categoryId=8&start=24&mrd=0.9021185727219558&filterIds=1745912,1745729,1745750,1745254,1745034,1744996,1744970,1744646,1744743,1744838,1744567,1744308,1744225,1744727,1744649

https://www.pearvideo.com/category_loading.jsp?reqType=5&categoryId=8&start=36&mrd=0.6598737970838424&filterIds=1745912,1745729,1745750,1744642,1744353,1744377,1744291,1744127,1744055,1744106,1744126,1744040,1743939,1743997,1744012

对比上方三个url可见,除了其中的start, mrd以及filterIds不同之外,其余部分均为https://www.pearvideo.com/category_loading.jsp?reqType=5&categoryId=8&start=。其中start每次增长为12,即每次加载12段视频;mrd为一个随机数,filterIds即为视频资源的cid号。

2. 发送起始页请求

我们可以根据抓包获取到的信息构建请求,获取响应内容。全文将模仿scrapy框架的写法,将代码封装在一个类之中,再定义不同的函数实现各个阶段的功能。

#导入需要用到的模块 importrequests fromparselimportSelector fromfake_useragentimportUserAgent importrandom importjson importos

创建类并定义相关函数、属性

classPearVideo: def__init__(self,page): self.headers={ "User-Agent":UserAgent().chrome,#构建谷歌请求头 } self.page=page#设置要爬取的页数 self.base_url="https://www.pearvideo.com/category_loading.jsp?reqType=5&categoryId=8&start=" defstart_request(self): forpageinrange(self.page): start_url=self.base_url str(page*12)#拼接起始页url res=requests.get(start_url,headers=self.headers) ifres.status_code==200: #将获取到的请求转换成一个parsel.selector.Selector对象,之后方便解析文本; #类似scrapy框架中的response对象,可直接调用re(), xpath()和css()方法。 selector=Selector(res.text) self.parse(selector)

获取到响应之后就可以解析响应文本了,在响应文本中我们可以提取到视频的详情页url及视频名称,代码如下:

梨视频怎么保存到电脑,Python爬取视频的几种方法(3)

3. 解析起始页响应获取视频名称、视频详情页url

defparse(self,response): videos=response.xpath("//div[@class='vervideo-bd']") forvideoinvideos: #拼接视频详情页url detail_url="https://www.pearvideo.com/" video.xpath("./a/@href").get() #提取视频名称 video_name=video.xpath(".//div[@class='vervideo-title']/text()").get() #将视频详情页url和视频名称传递给parse_detail方法,对详情页发送请求获取响应。 self.parse_detail(detail_url,video_name)

在浏览器中打开视频详情页,按F12观察浏览器渲染之后的代码可见视频资源的url, 如下图所示:

梨视频怎么保存到电脑,Python爬取视频的几种方法(4)

此处的视频资源url为:https://video.pearvideo.com/mp4/third/20211028/cont-1744727-11315812-110716-hd.mp4

但是实际获取视频详情页响应后,并没有找到视频资源的url,能找到的只有一张视频图片预览的url,如下图所示(可在浏览器视频详情页,鼠标右键查看网页源代码获取):

梨视频怎么保存到电脑,Python爬取视频的几种方法(5)

于是,我们再次针对视频详情页抓包,找到视频资源url的相关请求和响应内容,如下图所示:

梨视频怎么保存到电脑,Python爬取视频的几种方法(6)

梨视频怎么保存到电脑,Python爬取视频的几种方法(7)

其中的contId即为详情页响应的data-cid属性值(详见下文),而mrd为一个随机值,可通过random.random()生成,在发送请求的时候Referer必不可少,否则将无法获取到正确的响应内容。

点击preview,可以查看请求的响应结果,如下图所示:

梨视频怎么保存到电脑,Python爬取视频的几种方法(8)

在图中,我们可以得到一个后缀为mp4的srcUrl链接,这看起来像是我们需要的视频资源url,但是如果直接使用这个链接发送请求,将会提示如下错误:

梨视频怎么保存到电脑,Python爬取视频的几种方法(9)

对比观察浏览器渲染之后的视频资源url和抓包获取的视频资源url:

浏览器渲染:https://video.pearvideo.com/mp4/third/20211028/cont-1744727-11315812-110716-hd.mp4抓包获取:https://video.pearvideo.com/mp4/third/20211028/1637679343220-11315812-110716-hd.mp4

通过观察可得出,除了上文加黑标粗的部分不同外,其余部分均相同;而其中的1744727即为视频资源的data-cid属性值。

梨视频怎么保存到电脑,Python爬取视频的几种方法(10)

浏览器视频详情页中获取

于是我们可以将抓包所获取到的假的视频资源url中的1637679343220替换为cont-1744727(即视频data-cid属性值),即可获取到真正的视频资源url, 从而下载视频资源!

经过漫长的分析之后,终于可以着手写代码啦!

4. 针对视频详情页url发送请求,获取响应

defparse_detail(self,detail_url,video_name): detail_res=requests.get(detail_url,headers=self.headers) detail_selector=Selector(detail_res.text) init_cid=detail_selector.xpath("//div[@id='poster']/@data-cid").get()#提取网页中data-cid的属性值(初始cid) mrd=random.random()#生成随机数,构建mrd ajax_url=f"https://www.pearvideo.com/videoStatus.jsp?contId={init_cid}&mrd={mrd}" globalajax_header#将ajax_header设置为全局变量,以便在后续的函数中调用 ajax_header={"Referer":f"https://www.pearvideo.com/video_{init_cid}"} self.parse_ajax(ajax_url,init_cid,video_name)

5. 对视频详情页抓包,获取假的视频资源url

defparse_ajax(self,ajax_url,init_cid,video_name): ajax_res=requests.get(ajax_url,headers=ajax_header) fake_video_url=json.loads(ajax_res.text)["videoInfo"]["videos"]["srcUrl"]#获取假的视频资源url fake_cid=fake_video_url.split("/")[-1].split("-")[0]#从假的视频资源url中抽取假的cid real_cid="cont-" init_cid#真的cid等于cont-加上初始的cid #将假的视频资源url中假的cid(fake_cid)替换为真的cid(real_cid)即可得到真正的视频资源url啦!!! #这段代码,你品,你细品... real_video_url=fake_video_url.replace(fake_cid,real_cid) self.download_video(video_name,real_video_url)

6. 对视频资源url发送请求,获取响应

有了视频名称和视频资源url,就可以下载视频啦!!!

defdownload_video(self,video_name,video_url): video_res=requests.get(video_url,headers=ajax_header) video_path=os.path.join(os.getcwd(),"单线程视频下载") #如果不存在则创建视频文件夹存放视频 ifnotos.path.exists(video_path): os.mkdir(video_path) withopen(f"{video_path}/{video_name}.mp4","wb")asvideo_file: video_file.write(video_res.content) print(f"{video_name}下载完毕")

最后,定义一个run()方法作为整个类的入口,调用最开始的start_request()函数即可!(套娃,一个函数套另一个函数)

defrun(self): self.start_request() if__name__=='__main__': pear_video=PearVideo(3)#先获取它三页的视频资源 pear_video.run()

使用线程池下载视频

线程池这部分的代码总体和单线程类似,只是将其中的视频名称和视频资源url单独抽取出来,作为全局变量。获取视频名称和视频资源url这部分仍为单线程,仅在下载视频资源这部分才用了线程池处理,可以同时针对多个视频资源url发送请求获取响应。

主要代码如下:

classPearVideo: def__init__(self,page): self.headers={ "User-Agent":UserAgent().chrome, } self.page=page self.base_url="https://www.pearvideo.com/category_loading.jsp?reqType=5&categoryId=8&start=" self.video_list=[]#新增了video_list为全局变量,用来保存视频名称和视频资源url

1.获取真正的视频资源url代码

defparse_ajax(self,ajax_url,init_cid,video_name): ajax_res=requests.get(ajax_url,headers=ajax_header) fake_video_url=json.loads(ajax_res.text)["videoInfo"]["videos"]["srcUrl"] fake_cid=fake_video_url.split("/")[-1].split("-")[0] real_cid="cont-" init_cid real_video_url=fake_video_url.replace(fake_cid,real_cid) #video_dict每次请求都会刷新,最终保存到video_list中 video_dict={ "video_url":real_video_url, "video_name":video_name } self.video_list.append(video_dict)

2. 多线程下载视频资源代码

defdownload_video(self,video_dict):#此处传递的是一个字典而非video_list这个列表 video_res=requests.get(video_dict["video_url"],headers=ajax_header) video_path=os.path.join(os.getcwd(),"线程池视频下载") ifnotos.path.exists(video_path): os.mkdir(video_path) withopen(f"{video_path}/{video_dict['video_name']}.mp4","wb")asvideo_file: video_file.write(video_res.content) print(f"{video_dict['video_name']}下载完毕")

3. 启动多线程

if__name__=='__main__': pear_video=PearVideo(2) pear_video.run() pool=ThreadPoolExecutor(4)#此处的4表示每次只开启4个线程下载视频资源 #此处的map方法和Python自带的map(x,y)含义类似,即将可迭代对象y中的每一个元素执行函数x。 pool.map(pear_video.download_video,pear_video.video_list)

使用协程下载视频

使用协程下载视频资源中最为重要的三个库为asyncio(创建协程对象),aiohttp(发送异步请求),aiofiles(异步保存文件)。

重点:

1)在函数前加上async关键字,函数即被创建为一个协程对象;2)协程对象中所有需要io耗时操作的部分均需使用await将任务挂起;3)协程对象不能直接运行,需要创建一个事件循环(类似无限循环),然后再运行协程对象。

注意:

1)不能使用requests发送异步请求,需要使用aiohttphttpx;2)不能直接使用open()保存文件,需要使用aiofiles进行异步操作保存。

主要代码如下

#将视频资源url和视频名称作为全局变量 self.video_urls=[] self.video_names=[]

1.定义协程对象下载视频

#下载视频信息 asyncdefdownload_videos(self,session,video_url,video_name,video_path): #发送异步请求 asyncwithsession.get(video_url,headers=ajax_header)asres: #获取异步响应,前面必须加上await,表示挂起 content=awaitres.content.read() #异步保存视频资源到电脑本地 asyncwithaiofiles.open(f"{video_path}/{video_name}.mp4","wb")asfile: print(video_name "下载完毕...") awaitfile.write(content)

2. 创建main()运行协程对象

asyncdefmain(self): video_path=os.path.join(os.getcwd(),"协程视频下载") ifnotos.path.exists(video_path): os.mkdir(video_path) asyncwithaiohttp.ClientSession()assession:#创建session,保持会话 #创建协程任务,每一个视频资源url即为一个协程任务 tasks=[ asyncio.create_task(self.download_videos(session,url,name,video_path)) forurl,nameinzip(self.video_urls,self.video_names) ] #等待所有的任务完成 done,pending=awaitasyncio.wait(tasks)

3. 调用整个类并运行协程对象

if__name__=='__main__': pear_video=PearVideo(3) pear_video.run() loop=asyncio.get_event_loop()#创建事件循环 loop.run_until_complete(pear_video.main())#运行协程对象

在保存视频的时候,如果视频名称中含有"\", "/", "*", "?", "<", ">", "|"在内的非法字符,视频将无法保存,程序将报错,可用如下代码过滤视频名称:

defrename(self,name): stop=["\\","/","*","?","<",">","|"] new_name="" foriinname: ifinotinstop: new_name =i returnnew_name

在使用多线程和协程下载视频资源这部分代码中都是使用单线程和线程池/协程结合,均是在获取到视频名称和视频资源url后再针对视频资源发送请求,获取响应,此部分代码仍有待优化,如使用生产者/消费者模式一边生产视频资源url,一边根据url下载视频;而协程部分也可将其它需要发送网络请求的部分修改为协程模式,从而提高下载速度。

总结

下载梨视频的视频资源难点在于破解真正的视频资源url, 先后需要对视频起始页(主页)发送请求,再对视频详情页发送请求,然后再对视频详情页抓包获取真正的视频资源url,最后再针对视频资源url发送请求,下载视频资源。其中线程池和协程的部分仍有待优化,以便更好地提高下载效率!

,
图文教程
相关文章
热门专题
推荐软件
奇热小说
奇热小说
下载
QQ2019手机版
QQ2019手机版
下载
王者荣耀
王者荣耀
下载
百度浏览器迷你版
百度浏览器迷你版
下载
2345浏览器手机版
2345浏览器手机版
下载
网易邮箱
网易邮箱
下载
爱奇艺
爱奇艺
下载
网易云音乐
网易云音乐
下载
WPSOffice
WPSOffice
下载
优酷
优酷
下载
谷歌浏览器(Chrome)
谷歌浏览器(Chrome)
下载
迅雷看看播放器
迅雷看看播放器
下载
UC浏览器
UC浏览器
下载
QQ音乐
QQ音乐
下载
阿里旺旺买家版v9.12.10C官方版
阿里旺旺买家版v9.12.10C官方版
下载
360安全卫士v12.1官方版
360安全卫士v12.1官方版
下载
猜你喜欢
有活动youhuodong
有活动youhuodong
下载
牛约外卖商户端
牛约外卖商户端
下载
神州专车iPad版V1.9.0
神州专车iPad版V1.9.0
下载
唯讯电脑硬件信息采集工具v1.0测试版
唯讯电脑硬件信息采集工具v1.0测试版
下载
上古卷轴5重制版月亮夜空美化MOD
上古卷轴5重制版月亮夜空美化MOD
下载
猫咪杂货红包版
猫咪杂货红包版
下载
大家好给大家介绍一下表情包
大家好给大家介绍一下表情包
下载
养好娃电脑版
养好娃电脑版
下载
No2g电脑版
No2g电脑版
下载
猪猪惠返
猪猪惠返
下载
游戏王卡片制作器
游戏王卡片制作器
下载
福建干部网络学院
福建干部网络学院
下载
神奇视频
神奇视频
下载
微氧ios版
微氧ios版
下载
htclockscreen.apk
htclockscreen.apk
下载
我要当老司机
我要当老司机
下载