Python下载M3U8加密视频示例
生活随笔
收集整理的這篇文章主要介紹了
Python下载M3U8加密视频示例
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
大家好,我是小小明。
最近看到幾個視頻網站的地址依然是m3u8格式,不禁有了使用python進行下載的想法,雖然下載m3u8格式視頻的工具很多,但如果我們自行編碼就能應對更多的情況。
關于m3u8的基礎知識可以參考:Python實時下載B站直播間視頻(M3U8視頻流)
下面我們將使用Python下載m3u8格式的加密離線視頻流。
游覽器抓包過濾能夠獲取該影片的m3u8播放地址:
首先,測試一下該地址:
import m3u8headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36" }playlist = m3u8.load(uri='https://vod8.wenshibaowenbei.com/20210628/g4yNLlI7/index.m3u8', headers=headers) playlist.data {'media_sequence': None,'is_variant': True,'is_endlist': False,'is_i_frames_only': False,'is_independent_segments': False,'playlist_type': None,'playlists': [{'uri': '/20210628/g4yNLlI7/1000kb/hls/index.m3u8','stream_info': {'program_id': 1,'bandwidth': 1000000,'resolution': '1280x720'}}],'segments': [],'iframe_playlists': [],'media': [],'keys': [],'rendition_reports': [],'skip': {},'part_inf': {},'session_data': [],'session_keys': []}從結果看到,這是一個嵌套的地址。
所以寫個方法解析真實地址:
import m3u8headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36" }def get_real_url(url):playlist = m3u8.load(uri=url, headers=headers)return playlist.playlists[0].absolute_urireal_url = get_real_url('https://vod8.wenshibaowenbei.com/20210628/g4yNLlI7/index.m3u8') real_url 'https://vod8.wenshibaowenbei.com/20210628/g4yNLlI7/1000kb/hls/index.m3u8'解析真實地址的加密key:
playlist = m3u8.load(uri=real_url, headers=headers) key = playlist.keys[-1] print(key.uri, key.method, key.iv) https://ts8.hhmm0.com:9999/20210628/g4yNLlI7/1000kb/hls/key.key AES-128 None可以看到密鑰下載地址和加密類型。
使用request下載密鑰:
import requestsr = requests.get(playlist.keys[0].uri, headers=headers) key = r.content key b'7ec5143edebbc899'可以單線程直接下載視頻:
import timen = len(playlist.segments) size = 0 start = time.time() for i, seg in enumerate(playlist.segments, 1):r = requests.get(seg.absolute_uri, headers=headers)data = r.contentdata = AESDecrypt(data, key=key, iv=key)size += len(data)with open("reusult.mp4", "ab") as f:f.write(data)print(f"\r下載進度({i}/{n}),已下載:{size/1024/1024:.2f}MB,下載已耗時:{time.time()-start:.2f}s", end=" ") 下載進度(1435/1435),已下載:424.69MB,下載已耗時:850s單線程下載,好處是不會產生多余的文件,缺點是速度太慢了,一個視頻下載了10多分鐘。
下面我們整理一下完整的代碼:
單線程視頻下載的完整代碼
import time from Crypto.Util.Padding import pad from Crypto.Cipher import AES import requests import m3u8headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36" }def get_real_url(url):playlist = m3u8.load(uri=url, headers=headers)return playlist.playlists[0].absolute_uridef AESDecrypt(cipher_text, key, iv):cipher_text = pad(data_to_pad=cipher_text, block_size=AES.block_size)aes = AES.new(key=key, mode=AES.MODE_CBC, iv=key)cipher_text = aes.decrypt(cipher_text)return cipher_textdef download_m3u8_video(url, save_name):real_url = get_real_url(url)playlist = m3u8.load(uri=real_url, headers=headers)key = requests.get(playlist.keys[-1].uri, headers=headers).contentn = len(playlist.segments)size = 0start = time.time()for i, seg in enumerate(playlist.segments, 1):r = requests.get(seg.absolute_uri, headers=headers)data = r.contentdata = AESDecrypt(data, key=key, iv=key)size += len(data)with open(save_name, "ab" if i != 1 else "wb") as f:f.write(data)print(f"\r下載進度({i}/{n}),已下載:{size/1024/1024:.2f}MB,下載已耗時:{time.time()-start:.2f}s", end=" ")download_m3u8_video('https://vod8.wenshibaowenbei.com/20210628/g4yNLlI7/index.m3u8', '走進家門.mp4')多線程下載改造
對于多線程,由于下載的文件可能出現間斷,所以我們不能直接追加到目標視頻中,可以先下載下來,最后統一合并并刪除。
先創建ts視頻下載的方法:
import os import requestsdef download_ts(url, key, i):r = requests.get(url, headers=headers)data = r.contentdata = AESDecrypt(data, key=key, iv=key)with open(f"tmp/{i:0>5d}.ts", "ab") as f:f.write(data)print(f"\r{i:0>5d}.ts已下載", end=" ")if not os.path.exists("tmp"):os.mkdir('tmp')任意下載一個片段測試一下:
import requests import m3u8def get_real_url(url):playlist = m3u8.load(uri=url, headers=headers)return playlist.playlists[0].absolute_uriheaders = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36" } real_url = get_real_url('https://vod8.wenshibaowenbei.com/20210628/g4yNLlI7/index.m3u8') playlist = m3u8.load(uri=real_url, headers=headers) key = requests.get(playlist.keys[-1].uri, headers=headers).contentdownload_ts(playlist.segments[0].absolute_uri, key, 1) 00001.ts已下載檢查該片段可以正常播放。
然后執行以下方法即可10個線程同時一起下載:
from concurrent.futures import ThreadPoolExecutorwith ThreadPoolExecutor(max_workers=10) as pool:for i, seg in enumerate(playlist.segments):pool.submit(download_ts, seg.absolute_uri, key, i)經過一分20秒左右的時間,所有視頻流已經全部下載完畢,比單線程的速度快了不止10倍。
最后我們實現文件的合并和ts臨時文件清除:
import globwith open('video.mp4', 'wb') as fw:files = glob.glob('tmp/*.ts')for file in files:with open(file, 'rb') as fr:fw.write(fr.read())print(f'\r{file}已合并!總數:{len(files)}', end=" ")os.remove(file)執行后,已經在1秒左右時間合并并清除完臨時文件。
多線程下載的完整代碼
import glob from concurrent.futures import ThreadPoolExecutor import m3u8 import os import requests from Crypto.Util.Padding import pad from Crypto.Cipher import AES import requestsheaders = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36" }def download_ts(url, key, i):r = requests.get(url, headers=headers)data = r.contentdata = AESDecrypt(data, key=key, iv=key)with open(f"tmp/{i:0>5d}.ts", "ab") as f:f.write(data)print(f"\r{i:0>5d}.ts已下載", end=" ")def get_real_url(url):playlist = m3u8.load(uri=url, headers=headers)return playlist.playlists[0].absolute_uridef AESDecrypt(cipher_text, key, iv):cipher_text = pad(data_to_pad=cipher_text, block_size=AES.block_size)aes = AES.new(key=key, mode=AES.MODE_CBC, iv=key)cipher_text = aes.decrypt(cipher_text)return cipher_textdef download_m3u8_video(url, save_name, max_workers=10):if not os.path.exists("tmp"):os.mkdir('tmp')real_url = get_real_url(url)playlist = m3u8.load(uri=real_url, headers=headers)key = requests.get(playlist.keys[-1].uri, headers=headers).contentwith ThreadPoolExecutor(max_workers=max_workers) as pool:for i, seg in enumerate(playlist.segments):pool.submit(download_ts, seg.absolute_uri, key, i)with open(save_name, 'wb') as fw:files = glob.glob('tmp/*.ts')for file in files:with open(file, 'rb') as fr:fw.write(fr.read())print(f'\r{file}已合并!總數:{len(files)}', end=" ")os.remove(file)download_m3u8_video('https://vod8.wenshibaowenbei.com/20210628/g4yNLlI7/index.m3u8', '走進家門.mp4')總結
以上是生活随笔為你收集整理的Python下载M3U8加密视频示例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: FL Studio21功能测评水果FL音
- 下一篇: RPLIDAR A3开箱实测