多线程批量下载、合并m3u8文件的python脚本

一、为什么会有这个脚本

    视频网站上面都要钱,第三方网站普遍慢,而且都是m3u8技术搭建的网站,MP4被分成非常多的ts文件,下载后必须合并才能保存和观看。有个下载神器叫xdm,能自动识别m3u8网页中的m3u8下载合并成MP4,而且是多线程下载,速度非常好,这个工具是我最近才发现的,而下载m3u8的脚本是多年前用ruby编写的,最近开始用python,才进行了改写。

二、python主程序,完成单个文件的多线程下载

    其中用到了ffmpeg工具,和wget命令行下载工具,为什么不要python的request呢,主要是还的编写断点续传,麻烦,另外一直使用linux惯了,wget用的多,就调用他了,同学们可自行下载windows版本,并加入PATH环境变量。

#!/usr/bin/python3

import sys
import re
import os
import threading
import time
import os.path

def download(url,ts):
    global time_out
    return(os.system("wget -U \"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36\" -cq -t 1 -T " + str(time_out) + " " + url))

def t_down(url,ts,f_arr):
    global down_i
    down_i += 1
    if download(url,ts)!=0:
        f_arr.append([url,ts])
        #print("redown "+url)
    down_i -= 1
        
print("\n")
print("usage:    m3u8 url mp4_filename thread_num time_out\n")
print("\n")

if len(sys.argv) < 3:
    sys.exit()
url=sys.argv[1]

#f_arr为ts文件列表
f_arr=[[]]

#判断是否为续传
if os.path.isfile("f_arr.txt"):
    with open("f_arr.txt", "r") as f1:
        for line in f1.readlines():
            arr = line.split(" ")
            f_arr[0].append(arr)
else:
    #下载m3u8文件
    f_m3u8 = re.search("\/([^\/]*\.m3u8)",url).group(1)
    pre_url = re.sub("\/([^\/]*\.m3u8)","",url)+"/"
    short_url=re.search("(^https:\/\/[^\/]*)\/",url).group(1)
    user_agent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"
    os.system("wget -U \"" + user_agent + "\" -O " + f_m3u8 + " " + url)
    #逐层解析,循环下载,得到最终的m3u8文件
    find_m3u8 = True
    while find_m3u8:
        find_m3u8 = False
        with open(f_m3u8, "r") as f1:
            lines = f1.readlines()
            if len(lines)<10:
                for line in lines:
                    if ".m3u8" in line:
                        url= pre_url + line
                        f_m3u8 = re.search("\/([^\/]*\.m3u8)",url).group(1)
                        pre_url = re.sub("\/([^\/]*\.m3u8)","",url)+"/"
                        short_url=re.search("(^https:\/\/[^\/]*)\/",url).group(1)
                        os.system("wget -U \"" + user_agent + "\" -O " + f_m3u8 + " " + url)
                        find_m3u8 = True
                        break
                
    #生成本地m3u8文件
    with open("filelist.m3u8", 'w') as f:
        with open(f_m3u8, "r") as f1:
            for line in f1.readlines():
                if ".ts" in line:
                    s1=re.search("([^\/]*\.ts)",line).group(1)
                    f.write(s1+"\n")
                    f_arr[0].append([pre_url +s1,s1])
                elif ".key" in line:
                    s1=re.search("[\/|\"]([^\/]*\.key)",line).group(1)
                    f.write('#EXT-X-KEY:METHOD=AES-128,URI="' + s1 +'"\n')
                    f_arr[0].append([pre_url +s1,s1])
                else:
                    f.write(line)

#wget计数,全局变量
down_i = 0 
#下载线程数
if len(sys.argv) > 3:
	down_num = int(sys.argv[3])
else:
	down_num = 20
#全局变量 超时时间,每次循环加一
if len(sys.argv) > 4:
	 time_out= int(sys.argv[4])
else:
	time_out = 20

#下载ts文件
i = 0
while len(f_arr[i])>0:
    time_out += 1
    k = 0
    while down_i > 0:
        k += 1
        if k <= time_out * down_i:
            time.sleep(1)
        else:
            os.system("taskkill /F /im wget.exe")
    #记录进度
    with open("f_arr.txt", 'w') as f:
        for pl in f_arr[i]:
            f.write(pl[0]+" "+pl[1]+"\n")
    j=0
    f_arr.append([])
    for pl in f_arr[i]:
        j += 1
        while True:
            if down_i < down_num:
                if j <= down_num:
                    time.sleep(1)
                print(str(i+1)+" down " + str(j) + "/" + str(len(f_arr[i])) +" "+ pl[0])
                t = threading.Thread(target=t_down,args=(pl[0],pl[1],f_arr[i+1]))
                t.start()
                break
            else:
                time.sleep(1)
    i += 1   
#转码
mp4 = sys.argv[2] + ".mp4"
while down_i > 0:
    time.sleep(1)
os.system("ffmpeg -loglevel quiet -allowed_extensions ALL -i filelist.m3u8  -c copy " + mp4)


三、多文件下载批处理

    把要下载的多个m3u8文件连接存入一个txt文件,并调用它,另外也可以打开自动关机,省点电。
    后两个参数分别是 线程数,默认20,单个ts文件超时时间,默认20秒,部分网站不允许太多下载线程,可适当减少。

@echo off
setlocal enabledelayedexpansion
echo,
echo usage: m3u8all m3u8_list_file thread_num time_out
echo,
set file=%1
set i=0
for /f "delims=" %%f in (%file%) do (
	set /a i=i+1
	echo !i!
	echo %%f
	mkdir !i!
	cd !i!
	python d:\src\python\m3u8\m3u8_wget.py %%f !i! %2 %3
	cd ..
)
rem shutdown /p


四、好的资源是下载的关键

    目前,网上有不少m3u8资源站,连续剧都整理好列表了,只许复制到一个txt文件中,就可以用上面脚本一键下载,并关机。非常方便,如果是单个文件xdm也是个不错的选择,不过xmd的合并成功率不高,我的合并方法是将下载的m3u8列表文件生成一个本地版本,再用ffmpeg内置命令合并的。本来ffmpeg就有下载和合并的功能,但是单线程操作,速度慢,文件合并不全。

你可能感兴趣的:(m3u8,ffmpeg,wget)