文章目录
0.项目名字:getMovies
仅做技术分享使用,如侵必删
1.获取下载链接
以某网站的视频为例(不同网站的规则不同,这是其中一种未加密的)
F12进入开发者模式,在Network中找到mp4文件(可以从Media中筛选)
Request URL对应的就是视频下载地址,也可以用下载器直接下载
2.下载准备
2.1.获取请求头
必须要有完整的请求头信息,否则要么无法访问URL,要么视频无法正确解码
像这个是不可用的。
此时可以尝试将下载链接复制到浏览器地址栏去重新打开
便可获得完整的请求头信息
附上自用的工具类源码,可将复制粘贴的请求头信息保存为字典类型
# -*- coding = utf-8 -*-
# @Time : 2021/5/11 16:50
# @Author : xyx-Eshang
# @File : headersUtil.py
# @software : PyCharm
import re
# 根据文本内容,获得headers
def getHeaders(headersStr):
headers = {}
headersList = re.findall(r':?(.*?): (.*)\n?', headersStr)
for headersTuple in headersList:
headers[headersTuple[0]] = headersTuple[1]
return headers
2.2.获取文件名
文件名在下载链接中可以看到,这里使用正则表达式将文件名从url中提取出来
2.3.创建好保存目录
保存路径对应的目录必须被提前创建好
如果路径不存在,直接用open()去调用是会报错的。
强调下面两个函数:
import os
os.mkdir("路径") # 创建文件夹
os.makedirs("路径") # 创建包括父级文件夹在内的各级文件夹
1) os.mkdir()按照参数去创建文件夹,但如果中间某一父级文件夹不存在,就会报错。以下方为例
os.mkdir("../abc/def") # 根据相对路径"../abc/def"创建def文件夹
如果…/abc这个文件夹存在,那么程序就可以正常执行;
但如果…/abc文件夹不存在,此时程序就会报错
2) os.makedirs()按照参数去逐级创建文件夹,能有效避免上述可能出现的错误,如果某一父级文件夹不存在,会一并创建。
3.下载文件
一切准备就绪以后,开始编写download()函数,需要的参数分别是
1) url
2) headers:请求头信息
3) full_file_name:完整的文件名
4) download_path:文件保存路径
open()的模式必须用bytes模式,
覆盖写入用"wb",追加写入(视频拼接)用"ab"
附源代码
def download(url, headers, full_file_name, download_path):
request = urllib.request.Request(url=url, method="GET", headers=headers)
print("正在下载:" + full_file_name, end="...")
try:
response = urllib.request.urlopen(request)
# 更换操作路径
os.chdir(download_path)
# 将下载的文件从内存拷贝到本地磁盘
file = open(full_file_name, "wb")
file.write(response.read())
file.close()
print("下载完成!")
except urllib.error.HTTPError as e:
if e.code == 404:
print("该文件不存在!")
else:
print(e)
4.进阶练习:m3u8加密视频的下载
有的网站上传的视频是经过m3u8加密处理过的
这类视频的特点是:
完整的视频会被切割成很多个扩展名为.ts的小片段
如下图所示,F12进入开发者工具,在XHR中筛选
由之前的内容可以得知,Request URL的内容就是这个视频片段的下载地址
而下载地址又和命名有关,仔细观察不难发现,文件的命名规则都是:
xxxxxxxx000.ts
xxxxxxxx001.ts
xxxxxxxx002.ts
有这样的规律就好办了,遍历下载所有的ts文件即可
这里针对核心部分,书写大致思路
4.1.遍历获得urlList列表和fullFileNameList列表
观察得知,一个视频的所有ts文件,url前面部分都是一样的
唯一的区别是后面的数字000、001、002…(或是00、01、02…)
因此可以用While True循环获取:
1) urlList:保存了所有的url
2) fullFileNameList:保存了所有的文件名(包括扩展名)
# 比如一共有3个ts文件,url分别是
# https://abcdefg01.ts
# https://abcdefg02.ts
# https://abcdefg03.ts
urlList = [] # 保存所有的url
fullFileNameList = [] # 保存所有的完整文件名
count = 0 # 计数器
baseUrl = "https://abcdefg" # url前面完全一致的部分
while True:
try:
# 处理fullFileName
# 由于数字是01、02、03,这里需要手动拼接
if(count < 10):
fullFileName == "0" + str(count) + ".ts"
else:
fullFileName == str(count) + ".ts"
# 保存到列表中
fullFileNameList.append(fullFileName)
# 处理url
url = baseUrl + fullFileName
# 保存到列表中
urlList.append(url)
except urllib.error.HTTPError as e:
# 报404时,说明已经遍历完毕,终止循环
if e.code == 404:
break
else:
print(e)
4.2.循环访问url并下载
循环访问urlList的元素即可
保存的文件名则是fullFileNameList的元素
整体和上面思路几乎一直,只是在外层嵌套了循环
详细说明将耗费大量篇幅,因此这里留给大家独立完成
4.3.合并文件
在下载好所有的ts文件以后,便可以将这些文件合并起来
特别注意
在前面命名的时候,一定要把前面的"0"给加上,否则视频将不会按照期望的顺序去执行合并!
4.3.1.使用cmd指令合并
copy /b 原视频路径.* 新视频路径\合并文件名
比如这里希望将D:\Python下的所有ts文件,合并成combinedFile.mp4
那么指令就是
copy /b D:\Python.* D:\Python\combinedFile.mp4
4.3.2.使用python的文件写入来实现
附源代码
def combineFiles(combinedFileName, downloadPath):
# 更换操作目录
os.chdir(downloadPath)
try:
# 若原有文件,则先移除文件
os.remove(combinedFileName)
except FileNotFoundError:
# 若原来没有该文件,不做任何操作
pass
# 获取所有文件名
allTsFileNames = os.listdir()
for tsFileName in allTsFileNames:
tsFile = open(tsFileName, "rb")
combinedFile = open(combinedFileName, "ab")
# 向目标文件追加内容
combinedFile.write(tsFile.read())
tsFile.close()
# 删除ts文件
os.remove(tsFileName)
print("合并完成")
os.chdir(defaultPath)
其中defaultPath是文件的默认操作路径,已在外层定义好