最新文章會在我的個人網站發佈:http://www.xiaokai1999.cn/
> 本教程只供個人學習,禁止用於商業,謝謝支持
禮拜六閒暇時刻在某站逛了一下,經常觀看科技、遊戲的我,發現了新大陸——小姐姐
好,開幹~~
文章目錄
1.分析地址
1.隨便找個視頻
(小姐姐對不起了,我要拿你做實驗了~~其實這個小姐姐長的確實不錯的)
因爲這種網站規模很大,所以一般這些視頻地址不會輕易的放在網頁源代碼裏,所以直接pass掉分析源代碼的過程。
2.後來我發現了!
我想到分享的原因是因爲(之前b站也是這麼一個套路,不過我最近去試了一下,好像不行了)
我們在分享裏找到點擊複製通用代碼。(這是一段HTML代碼,瞭解過HTML的同學知道iframe標籤是幹嘛的),分享的網站就在其中。
找到src後的網址,第一時間看到這個網址的時候我遲疑了,覺得好像和剛剛打開的網址一模一樣,但是仔細一看其實不一樣。
https://www.acfun.cn/player/ac11692688
3.分析分享頁面
這時候就得注意着網頁源代碼了。右鍵打開網頁源代碼。當看到源代碼的時候,有些同學的內心肯定是崩潰的:啊~~怎麼這麼亂七八糟的。
哈哈,其實做爬蟲最主要的還是5分仔細+5分技術吧,當我在逛這個網頁源代碼的時候看到了m3u8。
3.1 m3u8介紹
原理:將視頻或音頻流分片,並建立m3u8格式的索引,m3u8可以嵌套(最多支持一層嵌套)。可用於直播或者點播。
格式:m3u8是由獨立行組成的文本文件,行分成三類:
- 以#EXT開頭的表示是tag
- 僅有#表示是註釋
- uri行表示嵌套的m3u8文件,或者真正的分片流。
一級索引和二級索引中,給出的地址可能是相對地址/絕對地址。相對地址根據一級索引的地址更改。
通常一級索引會給出不同帶寬的下載鏈接,可以根據網速適配不同的下載鏈接,從而避免卡頓。
流格式可能是.ts .aac或者RFC支持的其他格式。
m3u8參數
- EXTINF:播放時間長度,單位s
- BANDWIDTH:帶寬
- EXT-X-ENDLIST:有這個參數,說明是點播,是完整的一段音頻或者視頻;沒有這個參數,說明是直播,需要不斷從二級索引中去獲取下一片段的鏈接
- EXT-X-MEDIA-SEQUENCE(可選): 播放列表的第一個音頻的序號,如64.m3u8中,有3個音頻,序號分別是12591742,12591743,12591744。如果不設置,默認爲第一個音頻鏈接序號爲0。可以沒有這個參數
- EXT-X-KEY:可能是加密的,具體見RFC
- EXT-X-TARGETDURATION:每片最大時長,單位s, #EXTINF應該小於這個值
例子
bipbopall.m3u8
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=200000
gear1/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=311111
gear2/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=484444
gear3/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=737777
gear4/prog_index.m3u8
prog_index.m3u8
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10, no desc
fileSequence0.ts
#EXTINF:10, no desc
fileSequence1.ts
#EXTINF:10, no desc
...
...
...
fileSequence178.ts
#EXTINF:10, no desc
fileSequence179.ts
#EXTINF:1, no desc
fileSequence180.ts
#EXT-X-ENDLIST
2.分析m3u8文件
就拿我們要獲取的m3u8來做例子吧。我們吧那一長段複製下來,打開這個網頁,會讓我們下載.m3u8後綴的文件。點擊下載。
https://tx-safety-video.acfun.cn/mediacloud/acfun/acfun_video/segment/xxx.m3u8?pkey=xxx&safety_id=xxx
我們以文本打開
#EXTM3U
#EXT-X-VERSION:4
#EXT-X-TARGETDURATION:5 #每片最大時長,單位s, #EXTINF應該小於這個值
#EXT-X-MEDIA-SEQUENCE:0 #播放列表的第一個音頻的序號,如64.m3u8中,有3個音頻,序號分別是12591742,12591743,12591744。如果不設置,默認爲第一個音頻鏈接序號爲0。可以沒有這個參數
#EXTINF:5.000000, #播放時間長度,單位s
xxx.ts?pkey=xxx&safety_id=xxx
其實.ts文件就是我們要下載的文件。(但是這個.ts和我們普通見到的不太一樣,其實這裏的ts需要加上pkey,safety_id兩個參數才能下載到視頻,相當於他們的加密方式吧)
這樣看起來很累,我們可以把這段分成3行來看(其實這裏還缺訪問的域名)
xxx.ts?
pkey=(xxx)
safety_id=(xxx)
1.找到.ts域名
按下ctrl+F12查看network裏是否有可靠的信息。
https://tx-safety-video.acfun.cn/mediacloud/acfun/acfun_video/segment/
我們就添加到上面獲取到的ts字符串前。(這個就是他其中的分段視頻了)
3.ffmpeg 視頻下載器介紹
1、libavformat:用於各種音視頻封裝格式的生成和解析,包括獲取解碼所需信息以生成解碼上下文結構和讀取音視頻幀等功能,包含demuxers和muxer庫;
2、libavcodec:用於各種類型聲音/圖像編解碼;
3、libavutil:包含一些公共的工具函數;
4、libswscale:用於視頻場景比例縮放、色彩映射轉換;
5、libpostproc:用於後期效果處理;
6、ffmpeg:是一個命令行工具,用來對視頻文件轉換格式,也支持對電視卡實時編碼;
7、ffsever:是一個HTTP多媒體實時廣播流服務器,支持時光平移;
8、ffplay:是一個簡單的播放器,使用ffmpeg 庫解析和解碼,通過SDL顯示;
在這組成部分中,需要熟悉基礎概念有
容器(Container)
容器就是一種文件格式,比如flv,mkv等。包含下面5種流以及文件頭信息。
流(Stream)
是一種視頻數據信息的傳輸方式,5種流:音頻,視頻,字幕,附件,數據。
幀(Frame)
幀代表一幅靜止的圖像,分爲I幀,P幀,B幀。
編解碼器(Codec)
是對視頻進行壓縮或者解壓縮,CODEC =COde (編碼) +DECode(解碼)
複用/解複用(mux/demux)
把不同的流按照某種容器的規則放入容器,這種行爲叫做複用(mux)
把不同的流從某種容器中解析出來,這種行爲叫做解複用(demux)
具體可以去看https://www.jianshu.com/p/3c8c4a892f3c(這個大佬寫的很詳細)
4.上代碼
1.網頁源代碼獲取
def requests_get(ac_url):
r = requests.get(ac_url,headers=headers).text
print(r)
if "出錯啦!" in r:
print("並沒有找到你想要的信息!")
return 0
a = get_informations(r)
return a
2.分別獲取m3u8下載地址
def get_informations(r):
informations=[]
filename=''
p1='';p2='';p3='';p4=''
urls = re.findall("[a-zA-z]+://[^\s]*",r)
for url in urls:
if "tx" in url:
informations = url.split("{")
for information in informations:
if '1080P' in information:
p1 = re.findall("[a-zA-z]+://[^\s]*",information)
p1 = "1080p地址:"+p1[0][0:p1[0].index("\\")]
elif '超清' in information:
p2 = re.findall("[a-zA-z]+://[^\s]*",information)
p2 = "超清地址:"+p2[0][0:p2[0].index("\\")]
elif "高清" in information:
p3 = re.findall("[a-zA-z]+://[^\s]*",information)
p3 = "高清地址:"+p3[0][0:p3[0].index("\\")]
elif "標清" in information:
p4 = re.findall("[a-zA-z]+://[^\s]*",information)
p4 = "標清地址:"+p4[0][0:p4[0].index("\\")]
# elif "title" in information:
# index = information.index("fileName")
# filename = information[index+11:information.index("\",\"id\"",index)]
return p1,p2,p3,p4
3.下載m3u8文件
def download_m3u8(ipt2):
print("正在下載m3u8")
download = ""
if ipt2 == '1':
download = a[0][5:]
elif ipt2=='2':
download = a[1][5:]
elif ipt2=='3':
download = a[2][5:]
elif ipt2=='4':
download = a[3][5:]
else:
print("輸入錯誤!")
return 0
r = requests.get(download,headers=headers,stream=True).text
with open(path+"/2.txt","w+") as f:
f.write(r)
f.close()
print("完成")
return 1
4.下載ts文件
def download_ts():
with open(path+"/2.txt","r+") as f:
t = f.readlines()
f.close()
print("開始下載---")
if not os.path.exists(path+"/vedio"):
os.mkdir(path+"/vedio")
l=0
for i in t:
if i[0]!="#" and len(i)>8:
s1 = i.split("?")
s2 = s1[1].split("&")
s3 = s2[0].split("=")
s4 = s2[1].split("=")
params={
"pkey":s3[1],
"safety_id":s4[1][:-1]
}
download_url = "https://tx-safety-video.acfun.cn/mediacloud/acfun/acfun_video/segment/"+s1[0]
# print(download_url)
r = requests.get(download_url,headers=headers,params=params,stream=True)
#print(r.url)
with open(path+"/vedio/"+str(l)+".ts","wb") as f:
for chunk in r.iter_content(chunk_size=1024 * 1024):
if chunk:
f.write(chunk)
f.close()
print("正在下載{0}.ts".format(l))
l+=1
time.sleep(1)
print("下載完成---")
5.合併ts文件
def involve_ts():
print("合併視頻")
ls = os.listdir(path+"/vedio/")
print(len(ls))
contect=""
for i in range(len(ls)):
contect += path+"/vedio/"+str(i)+".ts"
if i != len(ls)-1:
contect+="|"
print(contect)
cmd = "ffmpeg -i concat:\""+contect+"\" -acodec copy -vcodec copy -vbsf h264_mp4toannexb "+path+"/vedio/out.mp4"
os.system(cmd)
print("完成")
效果:
如要轉載請說明出處:https://blog.csdn.net/xiaokai1999/article/details/105690965