前一阵子我的一个好哥们小海知道我转行学了计算机,想要我帮忙下载某个网站的视频(因其只能在线观看,而且播放不够流畅~),本着男人不能说不行的原则,于是便有了本文。
声明:本文仅供技术交流,主要使用requests,threading,os,re等库,并且使用FFmpeg进行视频的合并。
01.获取视频播放链接
首先需要获取视频播放链接,打开视频页面,查看网页源代码,利用XPath便可轻易的获取视频标题以及播放链接。
02.获取m3u8文件
HTTP Live Streaming
(HLS)是一个由苹果公司提出的基于HTTP的流媒体网络传输协议。而HLS的m3u8,是一个ts的列表,其中ts是一种视频的封装格式。简单来说,整个视频是通过一个一个ts连续播放展示出来的。因此我们需要获取这个m3u8文件,从而得到所有的ts文件链接。
那么我们如何得到这个m3u8文件呢?经过观察,这个链接可以在视频播放页面的源代码中看到一丝端倪。
这个share链接打开之后可以看到m3u8文件的url链接,可以通过简单的正则表达式将其匹配。得到连接之后,我们就可以通过requests把这个m3u8文件下载到本地。
03.批量下载ts文件
根据下载的m3u8文件,加上url的前缀,便可获得ts文件的完整url连接,因为往往一个视频包含几百乃至上千个ts文件,这时多线程就派上了用场。
threading的使用可以大大加快下载的速度,由于电脑配置的限制,多线程的数目需要控制,不然就会频繁报错,甚至程序崩溃。经过测试,按100个线程同时开启,下载会非常稳健~ 所以我将ts文件按100个一组分类,最后不到100个分为一组。
代码语言:javascript复制def main(self):
self.get_shrae_url()
self.check_folder('m3u8')
for i in range(len(self.m3u8_urls)):
os.chdir(self.retval)
files,files_url=self.get_files(i)
print("*****************开始下载'{}',该视频共有{}个ts文件*****************".format(self.titles[i],len(files)))
segs=len(files)//100
for seg in range(segs 1):
tasks=[] # 线程池
left=100*seg
right=left 100 if seg!=segs else len(files)
for j in range(left,right):
task=threading.Thread(target=self.run, args=(i,files[j],files_url[j],))
tasks.append(task)
task.start()
time.sleep(1)
# 等待所有线程完成
for _ in tasks:
_.join()
print("*****************已经完成{}个ts文件下载!*****************".format(right))
print("*****************{}的所有ts文件已经完成下载!*****************".format(self.titles[i]))
self.merge(i)
self.delete(files)
def run(self,i,file,file_url):
ts_file_folder=self.titles[i]
try:
if os.path.exists('{}/{}'.format(ts_file_folder,file)):
pass
else:
r=requests.get(file_url,headers=self.headers)
with open('{}/{}'.format(ts_file_folder,file),'wb') as f:
f.write(r.content)
print("{}已下载".format(file))
except Exception as e:
print(str(e))
print("出现异常,正在自动重新下载!")
self.run(i,file,file_url)
04.ts合并成mp4
FFmpeg的视音频编解码功能非常太强大,几乎囊括了现存所有的视音频编码标准。因此我们通过其来将我们之前获取的ts文件合并成完整的mp4视频文件。
合并方法主要有两种,一是直接将需要合并的文件名通过“|”分隔
代码语言:javascript复制ffmpeg -i "concat:1.ts|2.ts" -c copy output.mp4
我采取了另外一种方法,编辑一个txt文本文件,罗列需要合并的子文件路径和名称,每一行的最前面需要加上“file”。
代码语言:javascript复制ffmpeg -f concat -i temp.txt -c copy output.mp4
利用os.system执行合并命令,其中要注意路径的问题,ffpmeg命令执行后在当前路径生成mp4文件。
代码语言:javascript复制 def merge(self,i):
time.sleep(3)
# 合并ts文件
os.chdir("{}/".format(self.titles[i]))
shell_str='ffmpeg -f concat -i temp.txt -c copy {}.mp4'.format(self.titles[i])
# print(shell_str)
os.system(shell_str)
print("*****************视频'{}'合并成功*****************".format(self.titles[i]))
05.删除所有ts文件
当视频完成合并之后,ts文件比较占据空间,我们需要将它们批量删除。这里files是所有的ts文件名的列表。
代码语言:javascript复制 def delete(self,files):
for file in files:
if os.path.exists(file):
os.remove(file)
print("*****************已删除所有ts文件!*****************")
知道了一个视频是如何下载的,批量下载多个视频便可信手拈来了。小海在体验高速视频下载之后,投来了羡慕的目光~
什么?你们只想要代码?后台回复“视频”即可