宅在家里的这段时间,本想安心看个电影,无耐网卡得厉害,看一会卡顿一会,搞得火大。
直接拿起我的万能武器“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')
声明:代码中的示例链接来采集于网络,仅用于技术的学习交流,不直接发布到文章里,如有需要可以留言。