写在前面
昨天上班的时候老哥问我能不能把cctv的视频下载下来,本着能播放就能下载的原则,我打开了F12。。。想获得完整的视频下载地址是有些难度的,不过把所有的视频流按顺序写进同一个二进制文件也是可行的办法。顺便尝试了一下从命令行获取参数,以及在下载过程中使用进度条。
用到的包
#爬取模块
import requests
#正则表达式、文件夹、系统变量
import re,os,sys
#进度条相关
from tqdm import tqdm
主要代码
根据参数获取url地址(这里提供一个url样例,是播放页面的地址)
if len(sys.argv) == 2:
url = sys.argv[1]
else:
sys.exit()
#url = 'https://tv.cctv.com/2020/11/26/VIDEkd2TSFPv3uK8Ias25jYL201126.shtml?spm=C28340.P1dzdfA9CsHZ.S29237.42'
浏览器标识(请求头),并创建“新闻联播”文件夹
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
}
if not os.path.exists('新闻联播'):
os.mkdir('新闻联播')
os.chdir('新闻联播')
获取guid和视频标题
def GetInfo():
try:
#请求视频地址,并编码为utf-8
req = requests.get(url = url,headers = headers)
req.encoding = 'utf-8'
#正则匹配guid(视频唯一标识符)
pattern_guid = re.compile('var\sguid\s=\s"(.*?)";')
#正则匹配网页中的视频标题
pattern_title = re.compile('var\scommentTitle\s=\s"(.*?)";')
guid = re.findall(pattern_guid,req.text)[0]
title = re.findall(pattern_title,req.text)[0].replace('/','')
#返回获取到的信息
return guid,title
except:
#如果出现异常则返回None
return None,None
获取视频流的总段数,并按顺序写进二进制文件
#guid,title为上面函数获取到的信息
def GetVideo(guid,title):
try:
#拼接出保存视频流信息文件的url地址(将花括号替换为了guid)
ts_list_url = "https://hls.cntv.lxdns.com/asp/hls/850/0303000a/3/default/{}/850.m3u8?maxbr=2048".format(guid)
#请求目标地址
req_ts = requests.get(url = ts_list_url,headers = headers)
#正则匹配,查询返回信息中共有多少个“.ts”
pattern_ts = re.compile("\.ts")
num = len(re.findall(pattern_ts,req_ts.text))
#创建二进制文件,根据title命名
f = open(title + '.mp4','wb')
print(title)
"""
调用进度条模块写循环,保存每一段视频流
desc为进度条的自定义提示信息,ncols为进度条长度
"""
for i in tqdm(range(num),desc = '正在下载...',ncols=80):
#拼接视频流的url,将两个花括号分别替换为guid、当前循环的i值
#中间的2000代表清晰度,即2k高清,其他选项有480、720、1200
ts_url = "https://hls.cntv.lxdns.com/asp/hls/2000/0303000a/3/default/{}/{}.ts".format(guid,i)
#请求与写入
req = requests.get(url = ts_url,headers = headers)
f.write(req.content)
#解除文件占用
f.close()
return 0
except Exception as e:
#返回错误信息
return e
调节程序的运行并捕捉错误
def run():
#调用函数获取guid和title
guid,title = GetInfo()
#如果返回值不是None
if guid and title:
#下载视频并捕捉返回值
debug = GetVideo(guid, title)
#如果返回值不是0,则打印错误信息
if debug != 0:
print(debug)
#退出程序
sys.exit()
else:
#如果返回值都是None,大概率是提供的url地址不对(当然也可能是网站有变动)
print('下载失败!请检查URL地址!')
sys.exit()
#入口函数
if __name__ == '__main__':
run()
如何使用
#cmd下切换到py文件所在路径
python spider_cctv.py https://tv.cctv.com/2020/11/26/VIDEkd2TSFPv3uK8Ias25jYL201126.shtml?spm=C28340.P1dzdfA9CsHZ.S29237.42
写在后面
其实没有什么反爬措施,主要是在分析url,以及匹配到视频对应的guid。请勿将视频用于非法途径!