python3爬蟲 爬取動漫視頻


起因

因為本人家里有時候網速不行,所以看動漫的時候播放器總是一卡一卡的,看的太難受了。閑暇無聊又F12看看。但是動漫網站卻無法打開控制台。這就勾起了我的興趣。正好反正無事,去尋找下視頻源。

但是這里事先說明,站長也不容易,提供這么好的動漫分享網站。這里就不把網站發出來了。喜歡這個站,想知道的可以聯系我QQ 530428277  。只是想實踐中鍛煉,沒有教授什么的含義。

第一天

思路

網站就匿了。F12無法打開,用開發者工具查看控制台,view-source查看源代碼。

 

隨便進入一部動漫查看源代碼,發現加了調試,並且禁止了F12,禁止了右鍵等。(防止偷看QAQ)

利用Chrome的Deactivate breakpoints(使所有斷點臨時失效),然后刷新查看

選擇集數后會跳轉到播放器的html頁面,重復相同的步驟。

找到了相關api

發現這個api是播放器的地址

getData.html?video_id=56073&json=xml是彈幕的數據

 

 

然后在api的主頁源代碼中發現了另一個動漫網站的地址

 

 

兩個站竟然幾乎一摸一樣相差無幾,難道是同一個站長。

然后api還是站點播放器的頁面都有一串請求。發現是360雲盤。

 

參數中的filename就是中文的urlencode了一下。

 

 

 

打開鏈接,就是Download的方法,而且直接是mp4格式。下載下來,可以直接觀看。

 

 

 

 所以該站點就是通過將api站點用播放器加載請求雲盤資源,然后主站iframe嵌套過來。

 如果這里要抓取的話,首先要知道動漫的id數字標識

 

然后進入頁面獲取不同集數的鏈接的ID即可,即56177,56714等。

這些數字ID對應了api鏈接中的nk參數,nk參數id對應了每部不同的動漫。簡單的說,就是每部MP4的標識

 

 獲取完集數ID后,進入api界面,通過NK對應數字ID參數。一集一集的獲取360雲盤內的mp4資源鏈接保存下來。

 

最后通過請求下載下來。

無意間測試了下搜索欄的xss,網站有寶塔。對於寶塔從沒有研究過。網站是Thinkphp3.2.1框架。看似都是html,是tp的偽靜態機制。

 

既然這里有搜索欄,那我們更加懶一下,不要自己去找動漫ID了,直接通過搜索欄中文搜索,然后得到動漫不同集數的不同ID保存,通過API調用獲取資源鏈接,后請求下載。

 

實現

 寫爬蟲廢眼睛,腦子疼,關鍵是不同的動漫進去有的是有正版版權的鏈接,有的沒有。

 

 

 

所以這里還得分情況。下面的代碼只是自己打了個草稿,想寫成類,寫了一小部分,就先打個草稿。

import random
import requests
import re
from bs4 import BeautifulSoup

def getheaders():
    user_agent_list = [ \
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1" \
        "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11", \
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6", \
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6", \
        "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1", \
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5", \
        "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5", \
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", \
        "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", \
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", \
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", \
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", \
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", \
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", \
        "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", \
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3", \
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24", \
        "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
    ]
    UserAgent=random.choice(user_agent_list)
    headers = {'User-Agent': UserAgent}
    return headers

#url='http://www.xxxx.com
DongM='虛構推理'
list0=[] #集數的NK標識
number=0 #統計集數
pattern = re.compile(r'/(\d+).html') #re規則
params={"searchText":DongM}
headers=getheaders()
fireq0=requests.get(url=url+'/Home/Index/search.html',params=params,headers=headers)
html0=fireq0.text
bf = BeautifulSoup(html0,"html.parser")
texts=bf.find_all('div',style="margin-left:18px;")[0].a['href']


fireq1=requests.get(url=url+texts,headers=headers)
html1=fireq1.text
bf = BeautifulSoup(html1,"html.parser")
texts=bf.find_all('section',class_="anthology")
if '其他1' in str(texts[0]) and '線路A' not in str(texts[0]):
    texts=texts[0].find_all('a',class_="circuit_switch1")
    number=int(texts[0].span['class'][0])
    for i in range(number):
        list0.append(pattern.findall(texts[i]['href'])[0])
    print(list0,'其他1線路')

elif '線路A' in str(texts[0]) and '其他1' not in str(texts[0]):
    texts=texts[0].find_all('a')
    number=int(texts[0].span['class'][0])
    for i in range(number):
        list0.append(pattern.findall(texts[i]['href'])[0])
    print(list0,'線路A')

else:
    print('解析線路出現問題')
#print(texts[0].find_all('a')[0]['href'])

這樣就獲取到了動漫的集數的NK標識

第二天

今天嘗試了下用urlretrieve去下載mp4動漫,發現應該是太大了。導致一直報錯。

今天又看到了一些文章,找一下還有沒有其他的下載方式。找到了requests的iter_content分塊傳輸,相當於下載字節流的方式。而不是整個mp4下下來。

還有直接可以調用瀏覽器selenium庫,這個后面再看。現場使用iter_content分塊傳輸嘗試。

並且發現了一些東西。

api界面的播放器請求頭中會帶着cookie和Range標識。但是探索發現,會發這么多請求,是因為你手動調整了播放器播放的位置,導致他會去重新請求,並且Range的位置,byte會改變到相應的位置對應的大小。

Range:0-

就是指定片頭加載到片尾,就是表示0-  。大致意思是

 

一但修改播放的進度,就會增加一個請求,Range也會從修改的地址,調節bytes

 

那如何知道總共需要下載的bytes有多大呢?可以從返回的Content-Length找到

再根據學習的一篇文章(下面給出了鏈接)可以實現類似斷點續傳。但是我發現只下載一分鍾的視頻流的話,無法觀看,應該是視頻完整性的加密的一些東西。只能一整部下下來才可以。

看文章的時候又看到了一個方便的庫,就不需要手動寫user-agent了

from fake_useragent import UserAgent

ua = UserAgent()
print(ua.ie)   #隨機打印ie瀏覽器任意版本
print(ua.firefox) #隨機打印firefox瀏覽器任意版本
print(ua.chrome)  #隨機打印chrome瀏覽器任意版本
print(ua.random)  #隨機打印任意廠家的瀏覽器  

這里我也想自動獲取它的片名,看到返回信息的headers頭中有,就通過切片獲得,不過需要小小的轉碼

 

 

測試出現錯誤

fake_useragent.errors.FakeUserAgentError: Maximum amount of retries reached 

解決辦法:

下載: https://fake-useragent.herokuapp.com/browsers/0.1.11 並另存為:fake_useragent.json
def get_header():
    location = os.getcwd() + '/fake_useragent.json'
    ua = fake_useragent.UserAgent(path=location)
    return ua.random  

這里就不用fake_useragent了。不如直接手動了=-=

通過tqdm模塊變成可視化進度條

 

基本的幾個功能已經完成了。獲取api功能,獲取視頻鏈接功能,下載功能。

這里呢我是想多線程去下載集數,每集用一個線程去下載。提高速度。

初稿完成。第三天改成類,看着舒服。這個與類的區別就是沒有變成函數。一開始就是沒這么想。沒搞函數。明天改成類,看的更清爽。

代碼部分(url,api已打碼):

import random
import os
import requests
import re
from bs4 import BeautifulSoup
from tqdm import tqdm
import threading

def getheaders():
    user_agent_list = [ \
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1" \
        "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11", \
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6", \
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6", \
        "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1", \
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5", \
        "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5", \
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", \
        "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", \
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", \
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", \
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", \
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", \
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", \
        "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", \
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3", \
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24", \
        "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
    ]
    UserAgent=random.choice(user_agent_list)
    headers = {'User-Agent': UserAgent}
    return headers

#下載功能
def down_from_url(url, dst="test.mp4"):
    response = requests.get(url, stream=True)
    dst=response.headers['Content-Disposition'][22:-1].encode('raw-unicode-escape').decode()
    file_size = int(response.headers['content-length'])
    if os.path.exists(dst):
        first_byte = os.path.getsize(dst)
    else:
        first_byte = 0
    if first_byte >= file_size:
        return file_size

    header = {"Range": f"bytes={first_byte}-{file_size}","user-agent":'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36'}
    pbar = tqdm(total=file_size, initial=first_byte, unit='B', unit_scale=True, desc=dst)
    req = requests.get(url, headers=header, stream=True)
    with open(dst, 'ab') as f:
        for chunk in req.iter_content(chunk_size=1024):
            if chunk:
                f.write(chunk)
                pbar.update(1024)
    pbar.close()

def main():
    threading_list=[]
    for i in list0:
        req0=requests.get(url='https://xxx.com/xxx.php?nk={0}'.format(i),headers=addheaders).text
        bf1=BeautifulSoup(req0,"html.parser")
        video_url=bf1.find_all('video',id="video")[0].source['src']
        #多線程
        added_Thread=threading.Thread(target=down_from_url,args=(video_url,))
        threading_list.append(added_Thread)
    for i in threading_list:
        i.start()
    for i in threading_list:
        i.join()


#搜索功能
url='http://www.xxxx.com'
DongM='虛構推理'
list0=[] #集數的NK標識
number=0 #統計集數
pattern = re.compile(r'/(\d+).html') #re規則
params={"searchText":DongM}
addheaders=getheaders()
fireq0=requests.get(url=url+'/Home/Index/search.html',params=params,headers=addheaders)
html0=fireq0.text
bf0 = BeautifulSoup(html0,"html.parser")
texts=bf0.find_all('div',style="margin-left:18px;")[0].a['href']

#獲取ID功能
fireq1=requests.get(url=url+texts,headers=addheaders)
html1=fireq1.text
bf = BeautifulSoup(html1,"html.parser")
texts=bf.find_all('section',class_="anthology")
if '其他1' in str(texts[0]) and '線路A' not in str(texts[0]):
    texts=texts[0].find_all('a',class_="circuit_switch1")
    number=int(texts[0].span['class'][0])
    for i in range(number):
        list0.append(pattern.findall(texts[i]['href'])[0])
    print(list0,'其他1線路')

elif '線路A' in str(texts[0]) and '其他1' not in str(texts[0]):
    texts=texts[0].find_all('a')
    number=int(texts[0].span['class'][0])
    for i in range(number):
        list0.append(pattern.findall(texts[i]['href'])[0])
    print(list0,'線路A')

else:
    print('解析線路出現問題')

if __name__ == '__main__':
    main()  

 

 

 

 

 

 

 

 

 

 

 

 

學習文章:

https://blog.csdn.net/qq_38534107/article/details/89721345

 

很感謝您看到最后,代碼已經放到github

https://github.com/hui1314/python-spider

 

 

知識科普:

 

206狀態碼

HTTP/1.1 206狀態碼表示的是:"客戶端通過發送范圍請求頭Range抓取到了資源的部分數據".這種請求通常用來:

  1. 學習http頭和狀態.
  2. 解決網路問題.
  3. 解決大文件下載問題.
  4. 解決CDN和原始HTTP服務器問題.
  5. 使用工具例如lftp,wget,telnet測試斷電續傳.
  6. 測試將一個大文件分割成多個部分同時下載.

這種響應是在客戶端表明自己只需要目標URL上的部分資源的時候返回的.這種情況經常發生在客戶端繼續請求一個未完成的下載的時候(通常是當客戶端加載一個體積較大的嵌入文件,比如視屏或PDF文件),或者是客戶端嘗試實現帶寬遏流的時候。

urlretrieve

鑒於一些網站會檢查user-agent的反爬機制。那就需要添加user-agent頭部標識

opener = urllib.request.build_opener()
opener.addheaders=[('user-agent','Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36')]
urllib.request.install_opener(opener)
req=urllib.request.urlretrieve(url='',filename='',reporthook=loading)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM