爬取网站加密视频
准备工作
目标网站
抓取视频分析1
从这里我们可以找到视频的网址
其中url1:https://vod10.bdzybf.com/20210818/sdtRN58R/index.m3u8是存放存放m3u8文件的文件的网址
我们用抓包工具可以看到这个网址的response是
第三行就是真正存放m3u8文件的网址
抓取视频分析2
我们可以发现这个网址和url1仅仅差了/1000kb/hls
我们请求到url2:https://vod10.bdzybf.com/20210818/sdtRN58R/1000kb/hls/index.m3u8
在response里面可以看到
其中第六行的METHOD是ts文件的解密方法,
URI是密匙网址,(我们需要拼接一下正确的网址)
每一行没有以#开头的就是ts文件的下载路径(同样需要拼接处理)
密匙
访问密匙网址,response是
这16位就是密匙
思路
由前面的文件等等我们最终会得到一些未解密的ts文件
而我们需要的是视频,所以我们需要解密合并
我们需要导入
开始爬虫
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'}
#正则表达式匹配网址
findm3u8_url=re.compile(r'<iframe id="mplay" name="mplay" src="/js/player/\?url=(?P<m3u8_url>.*?)&',re.S)
...
#找到m3u8文件网址
def find_m3u8_path(url):
resp=requests.get(url,headers=headers)
result=findm3u8_url.findall(resp.text)
if result.__len__() is not 1:
print("m3u8网址可能没有找对")
#这里偷了个懒直接拼接成url2
else:return result[0].replace("index.m3u8","1000kb/hls/index.m3u8")
#把response内容写到file_name里面
def download_m3u8file(file_name,m3u8_url):
if not os.path.exists(file_name):
os.system(f'mkdir {file_name}')
resp=requests.get(m3u8_url,headers=headers)
with open(file_name,mode="wb")as f:
f.write(resp.content)
#得到基础网址
def get_base_url(url):
base_url=url.replace("index.m3u8","")
return base_url
def main(url,newmp4path):
m3u8filepath="m3u8_file.txt"#存放那个含有密匙网址和解密方式的文件
m3u8_path=find_m3u8_path(url)
print("m3u8_path:",m3u8_path)
base_url=get_base_url(m3u8_path)
print("base_url:",base_url)
download_m3u8file(m3u8filepath,m3u8_path)
player_list=get_ts_list(m3u8filepath,base_url)
key=get_key(base_url+"key.key")
print("key:", key)
#得到ts的url列表player_list
def get_ts_list(file_name,base_url):
player_list=[]
with open(file_name,mode="r")as f:
for line in f:
if line.startswith("#"):
continue
ts_file_path=base_url+line.split("hls/")[1]
player_list.append(ts_file_path.replace("\n",""))
return player_list
#得到密匙
def get_key(key_url):
resp=requests.get(key_url,headers=headers)
return resp.content
接下来开始下载并解密ts文件
for lst_url in player_list:
url=base_url+lst_url
resp=requests.get(url)
cryptor = AES.new(key, AES.MODE_CBC, key)
#最好是创建一个临时文件夹用于存放这些ts文件
with open("临时文件夹/"+lst_url,mode="wb")as f:
f.write(cryptor.decrypt(resp.content.read()))
合并ts文件
#合并方法:copy /b 1.ts+2.ts+... new.mp4
#1.ts+2.ts是上面临时文件夹里面的ts文件路径
#new.mp4是合成的视频路径
merge_cmd = "copy /b " + temp_ts_file+"\*.ts " + creat_mp4_path
#cmd执行语句merge_cmd
os.system(merge_cmd)
附
其实我们可以用异步协程的方法来快速下载ts文件,经测试能提高8,9倍:
async def aiodown(ts_url,session,key,save_tempts_path):
name=ts_url.split("hls/")[1]
cryptor = AES.new(key, AES.MODE_CBC, key)
async with session.get(ts_url)as resp:
async with aiofiles.open(save_tempts_path+"/"+name,mode="wb")as f:
str=await resp.content.read()
await f.write(cryptor.decrypt(str).strip())
print(f"{name}下载完毕")
async def download_ts_file(player_list, key ,save_tempts_path):
# 任务元组
tasks = []
async with aiohttp.ClientSession() as session:
for ts_url in player_list:
task = asyncio.create_task(aiodown(ts_url, session, key,save_tempts_path))
tasks.append(task)
await asyncio.wait(tasks)
另外我们下载好的ts文件最好是全部改成0001,0002.ts这种形式方便合并
可以按照m3u8文件里面的顺序来依次重命名文件:
def change_file_name(m3u8_file,temp_ts_file):
lst=[]#用于存放xxx.ts
with open(m3u8_file,mode="r")as f:
for i,line in enumerate(f):
if line.startswith("#"):
continue
filename=line.split("hls/")[1].replace("\n","")
lst.append(filename)
print(lst.__len__(),lst)
for i in range(0,lst.__len__()):
if i<9:
os.rename(f"{temp_ts_file}\\"+lst[i],f"{temp_ts_file}\\000"+str(i+1)+".ts")
elif i<99:
os.rename(f"{temp_ts_file}\\"+lst[i],f"{temp_ts_file}\\00"+str(i+1)+".ts")
elif i<999:
os.rename(f"{temp_ts_file}\\"+lst[i],f"{temp_ts_file}\\0"+str(i+1)+".ts")
elif i<9999:
os.rename(f"{temp_ts_file}\\"+lst[i],f"{temp_ts_file}\\"+str(i+1)+".ts")
下载好视频后我们要把ts文件没用的都删掉:
def delete_tempfile(file):
del_cmd="del "+os.getcwd()+f"{file}\*.ts"
os.system(del_cmd)
爬取一部电视剧
只需要找到每一集的网址用上for循环即可