宅在家裏的這段時間,本想安心看個電影,無耐網卡得厲害,看一會卡頓一會,搞得火大。
直接拿起我的萬能武器“Python”,寫了個下載電影的小腳本,給大家分享一下!
有很多電影站的電影資源,是以m3u8的格式存在的,這種格式有的進行了加密,有了沒有加密,程序對這兩者進行了兼容處理。
源代碼使用python2.7開發,主要用到了這幾個包:requests,threadpool,Crypto
(1)導入包
import threadpool
import requests
import os
from Crypto.Cipher import AES
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
上面最後一行代碼,主要是爲了取消https的請求警告,警告雖然沒啥影響,但看着鬧心,所以用這行代碼就給去掉了。
(2)讀取m3u8
#讀取m3u8文件
def readm3u8(m3u8):
global key,base_url
arr = []
with open(m3u8,'r') as f:
while True:
line = f.readline()
if not line :
break;
#如果是加密格式,提取密鑰
if '#EXT-X-KEY' in line:
URI = line.split(',')[1]
uri_key = (URI.split('=')[1].replace('"','')).strip()
url0 = base_url + uri_key
r = requests.get(url0,verify=False)
key = r.content
if line[0]!='#':
arr.append(line[0:-1])
return arr
將m3u8文件讀到數組中備用。如果檢測到m3u8中指定了密鑰,還要把密鑰下載下來,放到變量key中,備用
(3)下載單個ts文件。
#下載單個TS文件
def downts(ts_path):
global key
url = ts_path
ts = os.path.basename(url)
if os.path.exists('tmp/' +ts):
return
print ts
r = requests.get(url,verify=False)
cnt = r.content
with open('tmp/' +ts,'wb+') as f:
if len(key)>0:
cryptor = AES.new(key, AES.MODE_CBC, key)
f.write(cryptor.decrypt(cnt))
else:
f.write(cnt)
m3u8本身是一個文本文件,把一個大的視頻文件,拆分成多個ts文件,以索引的形式記錄到這個文件中。這段代碼把每個文件下載下來,保存到本地;如果是加密格式,使用key進行解密後保存到本地。
(4)合併ts成一個mp4文件
#合併ts文件
def merge(arr,filmpath):
with open(filmpath,'wb') as f1:
for ts in arr:
try:
f_ts = open('tmp/'+ts,'rb')
f1.write(f_ts.read())
f_ts.close()
except Exception:
continue
下載完成後,tmp文件夾下有一大堆的ts文件,雖然播放器能播放,但一個文件就幾秒種,看着更鬧心,趕緊合併吧。執行以上代碼後,久違的MP4電影就有了!
(5)主函數
def down(url,filmname):
global base_url
base_url,m3u8 = os.path.split(url)
base_url = base_url + '/'
r = requests.get(url,verify=False)
cnt = r.content
with open(m3u8,'w+') as f:
f.write(cnt)
arr = readm3u8(m3u8)
#線程池,使用20個線程
pool = threadpool.ThreadPool(20)
#構造 參數列表
var2 = [base_url + ts for ts in arr]
reqs = threadpool.makeRequests(downts, var2)
[pool.putRequest(req) for req in reqs]
#等待執行完畢
pool.wait()
#執行完畢合併成一個Mp4文件
merge(arr, 'tmp/' + filmname)
這是一個入口函數,主要是調度之前的幾個功能函數,同時,在這個主函數中使用的線程池,極大地提高了下載速度,這也是快速下載的核心代碼。你可以試試不用線程池的效果,那個速度會讓你感到絕望的!
- 完整代碼:
#coding=utf8
'''
Created on 2020年1月9日
根據m3u8鏈接下載電影
@author: Administrator
'''
import threadpool
import requests
import os
from Crypto.Cipher import AES
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
global key
key=''
def down(url,filmname):
global base_url
base_url,m3u8 = os.path.split(url)
base_url = base_url + '/'
r = requests.get(url,verify=False)
cnt = r.content
with open(m3u8,'w+') as f:
f.write(cnt)
arr = readm3u8(m3u8)
#線程池,使用20個線程
pool = threadpool.ThreadPool(20)
#構造 參數列表
var2 = [base_url + ts for ts in arr]
reqs = threadpool.makeRequests(downts, var2)
[pool.putRequest(req) for req in reqs]
#等待執行完畢
pool.wait()
#執行完畢合併成一個Mp4文件
merge(arr, 'tmp/' + filmname)
#合併ts文件
def merge(arr,filmpath):
with open(filmpath,'wb') as f1:
for ts in arr:
try:
f_ts = open('tmp/'+ts,'rb')
f1.write(f_ts.read())
f_ts.close()
except Exception:
continue
#下載單個TS文件
def downts(ts_path):
global key
url = ts_path
ts = os.path.basename(url)
if os.path.exists('tmp/' +ts):
return
print ts
r = requests.get(url,verify=False)
cnt = r.content
with open('tmp/' +ts,'wb+') as f:
if len(key)>0:
cryptor = AES.new(key, AES.MODE_CBC, key)
f.write(cryptor.decrypt(cnt))
else:
f.write(cnt)
#讀取m3u8文件
def readm3u8(m3u8):
global key,base_url
arr = []
with open(m3u8,'r') as f:
while True:
line = f.readline()
if not line :
break;
#如果是加密格式,提取密鑰
if '#EXT-X-KEY' in line:
URI = line.split(',')[1]
uri_key = (URI.split('=')[1].replace('"','')).strip()
url0 = base_url + uri_key
r = requests.get(url0,verify=False)
key = r.content
if line[0]!='#':
arr.append(line[0:-1])
return arr
if __name__ == '__main__':
#無加密,西遊記
url = 'https://xxxxxxxxx.com/20200220/5zpOS6bB14nsUXgM/index.m3u8'
#有加密,狄仁傑
#url = 'https://xxxxxxxxxx.com/20190425/xiqWxfle/950kb/hls/index.m3u8'
down(url,'xyj.mp4')
聲明:代碼中的示例鏈接來採集於網絡,僅用於技術的學習交流,不直接發佈到文章裏,如有需要可以留言。