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