Python快速下載M3U8電影

宅在家裏的這段時間,本想安心看個電影,無耐網卡得厲害,看一會卡頓一會,搞得火大。

直接拿起我的萬能武器“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')

聲明:代碼中的示例鏈接來採集於網絡,僅用於技術的學習交流,不直接發佈到文章裏,如有需要可以留言。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章