辣條君寫爬蟲5【戀愛綜藝《心動的訊號》視訊下載】
最近辣條君看到一部綜藝《心動的訊號》,打算看一看,學一學年輕人該怎樣談戀愛。可是,某訊視訊要會員,從小艱苦樸素的辣條君當然選擇白嫖了。於是乎,發現有線上資源哎~
Tip:本文僅供學習與交流,切勿用於非法用途!!!請大家支援正版!!!
分析與思路
今天爬取的頁面是http://www.ikanmv.com/k/39050.html
。底下一共有10集。
我們隨便開啟一集,點選network
,發現視訊是m3u8
格式的。有兩個m3u8格式檔案,第一個是一些限制條件,真正的m3u8列表。後面就是列表中逐條下載的ts檔案。
我們的目標是,把一集的所有ts檔案下載下來,通過ffmpeg
軟體進行拼接、轉化,最終生成一個.mp4檔案。ffmpeg
連結: https://pan.baidu.com/s/1_1htbaRQP_6y_G2xHOmWBw
提取碼: wivw
其實直接用ffmpeg
也可以根據m3u8列表連線直接下載,但是速度較慢,咱們程式碼中使用多程序,加速下載。
不過還有個問題,經過測試,ffmpeg
合併ts檔案,一次性最多合併4、5百個(每集ts檔案大概在1500~2000個之間),再多就會報錯,所以我們先以300個ts檔案為1組,將他們合併一下,得到幾個大個的ts檔案,再將這幾個大個的ts檔案合併成一集一個整個的ts檔案,再轉化mp4。
所以我們的程式碼流程為:下載某集所有ts檔案->合併成幾個大個的ts檔案->合併成一個ts檔案->轉化成mp4->刪除沒用的ts檔案
程式碼實現
首先建立一個資料夾D:\ts
用於存放ts檔案。
根據上節的程式碼流程,我們可以寫出主函式,幾個方法逐步實現:
if __name__ == '__main__': urls = [ 'https://zy.kubozy-youku-163-aiqi.com/20190710/13975_9273f090/1000k/hls/index.m3u8', 'https://zy.kubozy-youku-163-aiqi.com/20190717/14563_0eca69d7/1000k/hls/index.m3u8', 'https://zy.kubozy-youku-163-aiqi.com/20190724/15218_7487f9e5/1000k/hls/index.m3u8' ] # 開始的集數 index = 4 for url in urls: # 獲取某集需要下載的ts列表 get_list = get_m3u8(url) # 下載ts檔案到本地 download('D:\\ts', get_list, url[0:-10]) # 合併 merge_ts('D:\\ts', str(index)+'.mp4') # 刪除沒用的 ts delete_ts('D:\\ts') # 下一集 index = index + 1
我們模擬下載4~6集(由於沒找到規律,需要手動獲取幾集的第二個m3u8請求連線)
隨便點選兩個ts連線就會發現,某一集的ts檔案請求前面都是一樣的,最後拼接上xxxxx00x.ts,然後get請求就可以得到某個ts視訊資源了。首先獲取某集所有ts檔案字尾,就是xxxxx00x.ts部分,實現一下get_m3u8
方法
# 獲取某集需要下載的ts列表
def get_m3u8(url):
result = requests.get(url)
lines = result.text.split('\n')
all_ts = []
for line in lines:
if line.endswith('.ts'):
all_ts.append(line)
return all_ts
然後下載到本地
# 下載一個ts檔案
def download_ts(ts, root, url):
res = requests.get(url+ts)
with open(root+"\\" + ts, 'ab') as f:
f.write(res.content)
f.flush()
print(ts+'下載完畢!')
# 下載ts檔案到本地
def download(root, get_list, url):
# 已經下載過的檔案
had_list = []
# 還有沒下載完的就繼續
while len(list(set(get_list).difference(set(had_list)))) > 0:
had_list = os.listdir(root)
# 還需要下載的
needs = list(set(get_list).difference(set(had_list)))
print('還需要下載個數為:'+str(len(needs)))
pool = Pool(10)
group = ([ts for ts in needs])
pool.map(partial(download_ts, root=root, url=url), group)
pool.close()
pool.join()
download
方法,即主函式中使用的方法。第一個引數root
是ts視訊下載的地址,第二個引數get_list
是某集所有ts檔案字尾(xxxxx00x.ts部分),第三個引數url
是某個ts請求字首。首先這裡用到了多程序,往期部落格介紹過,這裡照抄就好。
值得一提的時,這邊有個while
迴圈。因為多程序下載某集所有ts檔案過程中,我發現可能會造成某些ts檔案的丟失未下載,所以每次下載完成,我們獲取已下載完成的檔名稱(檔名稱就是ts字尾),和某集所有的ts檔案字尾,做差集。繼續下載這些丟失的,知道差集為空,就證明全部下載完畢。
接下來需要合併。
# 合併ts,由於一次無法合併那麼多,合併兩次
def merge_ts(root, name):
os.chdir(root)
all_ts = os.listdir(root)
# 計數器
counter = 0
big_list = []
per_list = []
# 將多個ts檔名,300為一組拼接在一起
for ts in all_ts:
if counter > 300:
counter = 0
big_list.append('+'.join(per_list))
per_list = []
else:
counter = counter+1
per_list.append(ts)
batch = 0
batch_ts = []
for big in big_list:
batch = batch + 1
batch_ts.append(str(batch)+'.ts')
os.system('copy /b ' + big + f' batch{batch}.ts')
shell_str = '+'.join(batch_ts)
# 第二次拼接
os.system('copy /b '+shell_str+' '+name)
這裡需要兩次合併,第二次合併和轉mp4格式是一個指令碼操作。這裡使用os.system
呼叫系統方法,由於我們的ffmpeg
已經放入到環境變數中,所以這裡就是直接操作ffmpeg
軟體了。
生成某集的mp4檔案之後,我們需要刪除根目錄下所有的.ts檔案,一來節約硬碟空間,二來為下一集下載.ts檔案清除干擾。
def delete_ts(root):
os.chdir(root)
all_file = os.listdir(root)
for file in all_file:
if file.endswith('.ts'):
os.remove(root+'\\'+file)
以上我們就可以下載到喜歡看的視訊了。喜歡的小夥伴快去試試吧~