PYTHON_异步爬虫(二)之梨视频爬取


一、梨视频获取分析、猜想、思考过程以及解决方案

  -1、get访问

    https://www.pearvideo.com/category_5

            

      2、访问:https://www.pearvideo.com/video_1720499进入某个视频的详细页面

                         

 

 

 问:这个响应包里的videoStatus.jsp文件里的链接是否就是该视频的链接?

访问:https://video.pearvideo.com/mp4/adshort/20210218/1613654018464-15608885_adpkg-ad_hd.mp4后:

 

  说明这个链接不是该视频实际的链接,但是必然存在联系!!

于是回过头来看看videoStatus.jsp

其headers为:

 

 

 响应包(Response)为: 


{
"resultCode":"1",
"resultMsg":"success", "reqId":"d417436d-8a6a-440a-846e-4457fbb7517b",
"systemTime": "1613654018464",
"videoInfo":{"playSta":"1","video_image":"https://image2.pearvideo.com/cont/20210218/cont-1720499-12554903.png","videos":{"hdUrl":"","hdflvUrl":"","sdUrl":"","sdflvUrl":"","srcUrl":"https://video.pearvideo.com/mp4/adshort/20210218/1613654018464-15608885_adpkg-ad_hd.mp4"}}
}

它是一个json形式的数据包

 

有什么联系?

  -先清除cookies

  -然后在某个视频详细页面点击视频播放按钮

           

 

 

         在这些文件中发现一个.mp4开头的文件,点击后,访问其Request URL:

                                                            https://video.pearvideo.com/mp4/adshort/20210218/cont-1720499-15608885_adpkg-ad_hd.mp4

         恰好可以访问该视频:

                 

 是不是觉得视频的实际链接和videoStatus.jsp中的链接特别相似?

        对比一下:

             

 

             只有一个部分不同,只需将cont-1720499替代掉红款部分就可以了。

接下来:

     思考:1、是不是所有的视频的有效链接都是videoStatus.jsp文件中的srcUrl 将其一部分替换成con-id,而其余不变?  其中id为一串数字

    为了验证猜想,点击另外一个视频发现,该视频的有效链接如下:

                  

 

    而其videoStatus.jsp文件的响应包中的json数据如下:

                

     观察发现,依旧是前面不变,只是将1613656560550替换成cont-1720285,从而得到这个视频的有效链接,即实际链接。

 

               2、这个id是什么?

         

     3、如何获取id?

                          这个id可以通过get方式请求访问https://www.pearvideo.com/category_5 从而得到其网页,再通过xpath解析出href,最后通过正则表达式得到id

                           (其中该正则表达式,即匹配模式为: ex='video_([0-9]+)'    #用于获取视频id的模式)

    4、如何获取响应包中的videoStatus.jsp内容?

      首先它是通过Request Url所获得的响应包

                            

                      https://www.pearvideo.com/videoStatus.jsp?contId=1720499&mrd=0.7680917929620115

                        观察一下这个链接,它有两个参数,一个是contId,另一个是mrd

                            

 

                      很明显contId的实参是该视频的id,而mrd是什么?

      

                      思考:mrd的值怎样得来的?

                                  

 

 

      猜想:不用mrd这个参数,只用contId这个参数依然可以得到videoStatus.jsp这个响应包

      为了验证猜想:直接访问这个链接:https://www.pearvideo.com/videoStatus.jsp?contId=1720499

                         

 

                   发现不能获取响应包中的有效内容。原因是:服务器进行了防盗处理。

     如何解决?

                             加个Referer :此内容用来标识这个请求是从哪个页面发过来的,服务器可以拿到这一信息并做相应的处理,如做来源统计、防盗处理等。

        因此在headers中增加 'Referer': detail_url 其中detail_url为 形如:https://www.pearvideo.com/video_1720499 这样的链接,即:该视频的详细页链接

                        用来表示访问https://www.pearvideo.com/videoStatus.jsp?contId=1720499这个请求是由https://www.pearvideo.com/video_1720499 这个网页发过来的。

             5、如何实现响应包中的链接与视频的有效链接部分替换?

                     -首先确定正则表达式:其匹配模式为ex1='[third,adshort]/.*?/(.*?)-.*?'  #需要被替换的模式

                     -其次根据匹配模式找到响应包中的链接需要被替换的部分

                     -然后确定替换的字符串

                    -最后用字符串的replace方法

              代码如下:

 1 session = requests.Session() #维持会话
 2 #从详细页中解析处视频的地址(url)
 3 json_url='https://www.pearvideo.com/videoStatus.jsp?contId='+con_id   #其中con_id为视频的编号id
 4 response=session.get(url=json_url,headers=headers)
 5 dic_obj=response.json()
 6 
 7 #被伪装的下载地址
 8 down_url=dic_obj['videoInfo']['videos']['srcUrl']
 9 
10 #将响应体中的链接转化为真实链接
11 need_replace=re.findall(ex1,down_url)[0]
12 
13 #替换的字符串
14 replaced='cont-'+con_id
15 #真实的下载地址
16 down_url=down_url.replace(need_replace,replaced)

 二、梨视频爬取流程图

  上述问题都分析清楚并解决后,综上:

 

三、代码

  1 import os
  2 import re
  3 import threading
  4 import time
  5 from multiprocessing.dummy import Pool
  6 from time import sleep
  7 
  8 import requests
  9 from lxml import etree
 10 #需求:爬取梨视频的视频数据
 11 headers = {
 12     'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'
 13 }
 14 
 15 urls = []  # 用于保存视频下载的所有链接
 16 def init():
 17 
 18     headers = {
 19         'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'
 20     }
 21     #原则:线程池处理的是阻塞且较为耗时的操作
 22 
 23     url='https://www.pearvideo.com/category_5'
 24     page_text=requests.get(url=url,headers=headers).text
 25 
 26     tree=etree.HTML(page_text)
 27 
 28     li_list=tree.xpath('//ul[@id="listvideoListUl"]/li')
 29 
 30     #获取响应体中的链接
 31     ex='video_([0-9]+)' #用于获取视频id的模式
 32     #需要被替换的模式
 33     ex1='[third,adshort]/.*?/(.*?)-.*?'
 34 
 35 
 36     for li in li_list:
 37         detail_url='https://www.pearvideo.com/'+li.xpath('./div/a/@href')[0]
 38         name=li.xpath('./div/a/div[2]/text()')[0]+'.mp4'
 39         con_id=re.findall(ex,li.xpath('./div/a/@href')[0])[0]
 40 
 41         #对详细页的url发起请求
 42         headers = {
 43             'Referer':detail_url,
 44             'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'
 45         }
 46         session = requests.Session()
 47         #从详细页中解析处视频的地址(url)
 48 
 49         json_url='https://www.pearvideo.com/videoStatus.jsp?contId='+con_id
 50         response=session.get(url=json_url,headers=headers)
 51         dic_obj=response.json()
 52         #被伪装的下载地址
 53         down_url=dic_obj['videoInfo']['videos']['srcUrl']
 54 
 55 
 56         #将响应体中的链接转化为真实链接
 57         need_replace=re.findall(ex1,down_url)[0]
 58         #print(need_replace)
 59 
 60         #替换的字符串
 61         replaced='cont-'+con_id
 62         #真实的下载地址
 63         down_url=down_url.replace(need_replace,replaced)
 64 
 65         dic={
 66             'name':name,
 67             'url':down_url
 68         }
 69         urls.append(dic)
 70 #下载视频
 71 def down(dic):
 72     url=dic['url']
 73     name=dic['name']
 74     print(name,'正在下载...')
 75 
 76     resPage=requests.get(url=url,headers=headers)
 77     #print(resPage.status_code)
 78 
 79     # 创建文件夹
 80     if not os.path.exists('../pearvideoLibs'):
 81         os.mkdir('../pearvideoLibs')
 82     video_path='../pearvideoLibs/'+name
 83     if resPage.status_code==200:
 84         with open(video_path,'wb') as fp:
 85             fp.write(resPage.content)
 86         print(name,'下载完成')
 87 
 88 if __name__=="__main__":
 89 
 90 
 91     '''
 92     time_start = time.time()
 93     init()
 94 
 95     for dic in urls:
 96         down(dic)
 97     time_end = time.time()
 98     print("%d second" % (time_end - time_start))
 99     '''
100 
101 
102     time_start = time.time()
103     init()
104     mypool = Pool(4)
105     mypool.map(down, urls)
106     time_end = time.time()
107 
108     mypool.close()
109     mypool.join()
110     print("%d second" % (time_end - time_start))

 运行结果:(注意:运行结果的视频名称会不一样,因为视频更新,但是结果的形式一样)

 

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM