Python爬蟲進(jìn)階之爬取某視頻并下載的實(shí)現(xiàn)
這幾天在家閑得無(wú)聊,意外的挖掘到了一個(gè)資源網(wǎng)站(你懂得),但是網(wǎng)速慢廣告多下載不了種種原因讓我突然萌生了爬蟲的想法。
下面說(shuō)說(shuō)流程:
一、網(wǎng)站分析
首先進(jìn)入網(wǎng)站,F(xiàn)12檢查,本來(lái)以為這種低端網(wǎng)站很好爬取,是我太低估了web主??梢钥吹轿宜⑿戮W(wǎng)頁(yè)之后,出現(xiàn)了很多js文件,并且響應(yīng)獲取的代碼與源代碼不一樣,這就不難猜到這個(gè)網(wǎng)站是動(dòng)態(tài)加載頁(yè)面。

目前我知道的動(dòng)態(tài)網(wǎng)頁(yè)爬取的方法只有這兩種:1、從網(wǎng)頁(yè)響應(yīng)中找到JS腳本返回的JSON數(shù)據(jù);2、使用Selenium對(duì)網(wǎng)頁(yè)進(jìn)行模擬訪問(wèn)。源代碼問(wèn)題好解決,重要的是我獲取的源代碼中有沒(méi)有我需要的東西。我再一次進(jìn)入網(wǎng)站進(jìn)行F12檢查源代碼,點(diǎn)擊左上角然后在頁(yè)面點(diǎn)擊一個(gè)視頻獲取一個(gè)元素的代碼,結(jié)果里面沒(méi)有嵌入的原視頻鏈接(看來(lái)我真的是把別人想的太笨了)。

沒(méi)辦法只有進(jìn)行抓包,去找js請(qǐng)求的接口。再一次F12打開網(wǎng)頁(yè)調(diào)試工具,點(diǎn)擊單獨(dú)的一個(gè)視頻進(jìn)行播放,然后在Network中篩選一下,只看HXR響應(yīng)(HXR全稱是XMLHTTPRequest,HMLHTTP是AJAX網(wǎng)頁(yè)開發(fā)技術(shù)的重要組成部分。除XML之外,XMLHTTP還能用于獲取其它格式的數(shù)據(jù),如JSON或者甚至純文本。)。

然后我一項(xiàng)一項(xiàng)的去檢查返回的響應(yīng)信息,發(fā)現(xiàn)當(dāng)我點(diǎn)擊播放的時(shí)候有后綴為.m3u8的鏈接,隨后就不斷刷新.ts文件的鏈接。

本來(lái)以為這就是原視頻的地址,我傻傻的直接從這個(gè)m3u8文件的headers中的URL直接進(jìn)入網(wǎng)站看看,結(jié)果傻眼了,獲取的是一串串.ts的文件名。

沒(méi)辦法只能百度君了。 科普了一下,也就說(shuō)我們必須把ts文件都下載下來(lái)進(jìn)行合并之后才能轉(zhuǎn)成視頻。

好了,視頻原地址弄清楚了,現(xiàn)在我們開始從一個(gè)視頻擴(kuò)展到首頁(yè)的整個(gè)頁(yè)面的視頻。再一次進(jìn)行抓包分析,發(fā)現(xiàn)一個(gè)API中包含了首頁(yè)的分類列表,然而里面并沒(méi)有進(jìn)入分類的URL地址,只有一個(gè)tagid值和圖片的地址。

于是我又在主頁(yè)點(diǎn)一個(gè)分類,再次進(jìn)行抓包,發(fā)現(xiàn)了一個(gè)API中包含了一個(gè)分類的單頁(yè)所有視頻的信息,通過(guò)他們的headers中的URL對(duì)比發(fā)現(xiàn),關(guān)于視頻的前一部分都是https:xxxxxxx&c=video,然后m=categories,通過(guò)字面意思我們都可以知道是分類,而每個(gè)tagid值對(duì)應(yīng)不同的分類。并且還發(fā)現(xiàn)每個(gè)URL中都追加了時(shí)間戳timestamp(這是web主為了確保請(qǐng)求不會(huì)在它第一次被發(fā)送后即緩存,看來(lái)還是有小心機(jī)?。?。當(dāng)m=lists,則是每個(gè)分類下的視頻列表,這里面我們就可以找到每個(gè)視頻對(duì)應(yīng)的ID了。



通過(guò)id我們可以獲取到視頻的詳細(xì)信息,并且還有m3u8文件URL地址的后面一部分。

好了,網(wǎng)站我們解析清楚了,現(xiàn)在開始堆碼了。
二、寫代碼
導(dǎo)入相關(guān)模塊
import requests
from datetime import datetime
import re
#import json
import time
import os
#視頻分類和視頻列表URL的前一段
url = "http://xxxxxxx/api/?d=pc&c=video&"
#m3u8文件和ts文件的URL前一段
m3u8_url ='https://xxxxxxxxxxxxx/videos/cherry-prod/2020/03/01/2dda82de-5b31-11ea-b5ae-1c1b0da2bc3f/hls/480/'
#構(gòu)造請(qǐng)求頭信息
header = {"user-agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2"}
#創(chuàng)建空列表存放視頻信息
vediomassag=''
#返回當(dāng)前時(shí)間戳
TimeStamp = int(datetime.timestamp(datetime.now()))
2.定義函數(shù),獲取網(wǎng)站首頁(yè)分類列表信息
#自定義函數(shù)獲取分類 def get_vediocategory(url, TimeStamp): cgURL = url + "m=categories×tamp=" + str(TimeStamp) + '&' response = requests.get(cgURL, headers=header) category = response.text # strrr='"%s"'%category # return strrr return category
3.定義函數(shù),通過(guò)上一個(gè)函數(shù)返回的分類信息,根據(jù)分類對(duì)應(yīng)的id,輸入id并傳輸?shù)疆?dāng)前URL中以便獲取分類下的視頻列表信息
#獲取分類后的視頻列表 def get_vedioList(url, TimeStamp, tagID): listURL = url + "m=lists×tamp=" + str(TimeStamp) + '&' + "page=1&tag_id=" + str(tagID) + "&sort_type=&is_vip=0" response = requests.get(listURL, headers=header) vedioLists = response.text return vedioLists
4.在視頻列表信息中獲取視頻對(duì)應(yīng)的id,獲取單個(gè)視頻詳細(xì)信息的URL
#獲取單個(gè)視頻的詳細(xì)信息 def get_vediomassages(url, TimeStamp, vedioID): videoURL = url + "m=detail×tamp=" + str(TimeStamp) + '&' + "&id=" + str(vedioID) response = requests.get(videoURL, headers=header) vediomassag = response.text return vediomassag
5.在視頻詳細(xì)信息中找到m3u8文件的下載地址,并將文件保存到創(chuàng)建的文件中
#將下載的m3u8文件放進(jìn)創(chuàng)建的ts列表文件中
def get_m3u8List(m3u8_url,vediomassag):
lasturl = r'"m3u8_720_url":"(.*?)","download_url'
last_url =re.findall(lasturl,vediomassag)
lastURL=m3u8_url+str(last_url)
response = requests.get(lastURL, headers=header)
tsList = response.text
cur_path='E:\\files' #在指定路徑建立文件夾
try:
if not os.path.isdir(cur_path): #確認(rèn)文件夾是否存在
os.makedirs(cur_path) #不存在則新建
except:
print("文件夾存在")
filename=cur_path+'\\t2.txt' #在文件夾中存放txt文件
f = open(filename,'a', encoding="utf-8")
f.write(tsList)
f.close
print('創(chuàng)建%s文件成功'%(filename))
return filename
6.將m3u8文件中的ts單個(gè)提取出來(lái)放進(jìn)列表中。
# 提取ts列表文件的內(nèi)容,逐個(gè)拼接ts的url,形成list
def get_tsList(filename):
ls = []
with open(filename, "r") as file:
line = f.readlines()
for line in lines:
if line.endswith(".ts\n"):
ls.append(line[:-1])
return ls
7.遍歷列表獲取單個(gè)ts地址,請(qǐng)求下載ts文件放進(jìn)創(chuàng)建的文件夾中
# 批量下載ts文件
def DownloadTs(ls):
length = len(ls)
root='E:\\mp4'
try:
if not os.path.exists(root):
os.mkdir(root)
except:
print("文件夾創(chuàng)建失敗")
try:
for i in range(length):
tsname = ls[i][:-3]
ts_URL=url+ls[i]
print(ts_URL)
r = requests.get(ts_URL)
with open(root, 'a') as f:
f.write(r.content)
f.close()
print('\r' + tsname + " -->OK ({}/{}){:.2f}%".format(i, length, i * 100 / length), end='')
print("下載完畢")
except:
print("下載失敗")
代碼整合
import requests
from datetime import datetime
import re
#import json
import time
import os
url = "http://xxxxxxxx/api/?d=pc&c=video&"
m3u8_url ='https://xxxxxxxxxxxxxxx/videos/cherry-prod/2020/03/01/2dda82de-5b31-11ea-b5ae-1c1b0da2bc3f/hls/480/'
header = {"user-agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2"}
vediomassag=''
TimeStamp = int(datetime.timestamp(datetime.now()))
#自定義函數(shù)獲取分類
def get_vediocategory(url, TimeStamp):
cgURL = url + "m=categories×tamp=" + str(TimeStamp) + '&'
response = requests.get(cgURL, headers=header)
category = response.text
# strrr='"%s"'%category
# return strrr
return category
#獲取分類后的視頻列表
def get_vedioList(url, TimeStamp, tagID):
listURL = url + "m=lists×tamp=" + str(TimeStamp) + '&' + "page=1&tag_id=" + str(tagID) + "&sort_type=&is_vip=0"
response = requests.get(listURL, headers=header)
vedioLists = response.text
return vedioLists
#獲取單個(gè)視頻的詳細(xì)信息
def get_vediomassages(url, TimeStamp, vedioID):
videoURL = url + "m=detail×tamp=" + str(TimeStamp) + '&' + "&id=" + str(vedioID)
response = requests.get(videoURL, headers=header)
vediomassag = response.text
return vediomassag
#將下載的m3u8文件放進(jìn)創(chuàng)建的ts列表文件中
def get_m3u8List(m3u8_url,vediomassag):
lasturl = r'"m3u8_720_url":"(.*?)","download_url'
last_url =re.findall(lasturl,vediomassag)
lastURL=m3u8_url+str(last_url)
response = requests.get(lastURL, headers=header)
tsList = response.text
cur_path='E:\\files' #在指定路徑建立文件夾
try:
if not os.path.isdir(cur_path): #確認(rèn)文件夾是否存在
os.makedirs(cur_path) #不存在則新建
except:
print("文件夾存在")
filename=cur_path+'\\t2.txt' #在文件夾中存放txt文件
f = open(filename,'a', encoding="utf-8")
f.write(tsList)
f.close
print('創(chuàng)建%s文件成功'%(filename))
return filename
# 提取ts列表文件的內(nèi)容,逐個(gè)拼接ts的url,形成list
def get_tsList(filename):
ls = []
with open(filename, "r") as file:
line = f.readlines()
for line in lines:
if line.endswith(".ts\n"):
ls.append(line[:-1])
return ls
# 批量下載ts文件
def DownloadTs(ls):
length = len(ls)
root='E:\\mp4'
try:
if not os.path.exists(root):
os.mkdir(root)
except:
print("文件夾創(chuàng)建失敗")
try:
for i in range(length):
tsname = ls[i][:-3]
ts_URL=url+ls[i]
print(ts_URL)
r = requests.get(ts_URL)
with open(root, 'a') as f:
f.write(r.content)
f.close()
print('\r' + tsname + " -->OK ({}/{}){:.2f}%".format(i, length, i * 100 / length), end='')
print("下載完畢")
except:
print("下載失敗")
'''# 整合所有ts文件,保存為mp4格式(此處函數(shù)復(fù)制而來(lái)未做實(shí)驗(yàn),本人直接在根目錄
命令行輸入copy/b*.ts 文件名.mp4,意思是將所有ts文件合并轉(zhuǎn)換成自己命名的MP4格式
文件。)
def MergeMp4():
print("開始合并")
path = "E://mp4//"
outdir = "output"
os.chdir(root)
if not os.path.exists(outdir):
os.mkdir(outdir)
os.system("copy /b *.ts new.mp4")
os.system("move new.mp4 {}".format(outdir))
print("結(jié)束合并")'''
if __name__ == '__main__':
# 將獲取的分類信息解碼顯示出來(lái)
# print(json.loads(get_vediocategory(url, TimeStamp)))
print(get_vediocategory(url, TimeStamp))
tagID = input("請(qǐng)輸入分類對(duì)應(yīng)的id")
print(get_vedioList(url, TimeStamp, tagID))
vedioID = input("請(qǐng)輸入視頻對(duì)應(yīng)的id")
get_vediomassages(url, TimeStamp, vedioID)
get_m3u8List(m3u8_url,vediomassag)
get_tsList(filename)
DownloadTs(ls)
# MergeMp4()
此時(shí)正在下載

三、問(wèn)題:
首先對(duì)于這種網(wǎng)站采取的爬取方法有很多,而我的方法相對(duì)來(lái)說(shuō)有點(diǎn)太低端了,并且我也 是第一次寫博客,第一次寫爬蟲這類程序,在格式上命名上存在著很多問(wèn)題,函數(shù)的用法不全面。并且在運(yùn)行的時(shí)候效率低速度太慢。在獲取分類列表和視頻列表時(shí),因?yàn)槭荍SON文件,需要轉(zhuǎn)碼,過(guò)程太多加上程序不夠穩(wěn)定我就注釋掉了。還有就是對(duì)于這種動(dòng)態(tài)網(wǎng)頁(yè)了解不夠,所以學(xué)爬蟲的小伙伴一定要把網(wǎng)頁(yè)的基礎(chǔ)搞好。希望各位大佬多指正多批評(píng),讓我們這些小白一起努力學(xué)好Python。
注意:里面所有的鏈接我的給打碼了,怕被和諧了哈哈
到此這篇關(guān)于Python爬蟲進(jìn)階之爬取某視頻并下載的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Python 爬取某視頻并下載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺談Python中用datetime包進(jìn)行對(duì)時(shí)間的一些操作
下面小編就為大家?guī)?lái)一篇淺談Python中用datetime包進(jìn)行對(duì)時(shí)間的一些操作。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-06-06
tensorflow ckpt模型和pb模型獲取節(jié)點(diǎn)名稱,及ckpt轉(zhuǎn)pb模型實(shí)例
今天小編就為大家分享一篇tensorflow ckpt模型和pb模型獲取節(jié)點(diǎn)名稱,及ckpt轉(zhuǎn)pb模型實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-01-01
Python使用PyYAML庫(kù)讀寫yaml文件的方法
這篇文章主要介紹了Python使用PyYAML庫(kù)讀寫yaml文件的方法,包括YAML基本概念介紹及YAML語(yǔ)法知識(shí),結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04
python Autopep8實(shí)現(xiàn)按PEP8風(fēng)格自動(dòng)排版Python代碼
這篇文章主要介紹了python Autopep8實(shí)現(xiàn)按PEP8風(fēng)格自動(dòng)排版Python代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
詳解pandas刪除缺失數(shù)據(jù)(pd.dropna()方法)
這篇文章主要介紹了pandas刪除缺失數(shù)據(jù)(pd.dropna()方法),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06
python標(biāo)準(zhǔn)庫(kù)學(xué)習(xí)之sys模塊詳解
sys模塊是最常用的和python解釋器交互的模塊,sys模塊可供訪問(wèn)由解釋器(interpreter)使用或維護(hù)的變量和與解釋器進(jìn)行交互的函數(shù),下面這篇文章主要給大家介紹了關(guān)于python標(biāo)準(zhǔn)庫(kù)學(xué)習(xí)之sys模塊的相關(guān)資料,需要的朋友可以參考下2022-08-08

