2021-09-10

爬取网站加密视频

准备工作

目标网站

测试电影网站

抓取视频分析1

从这里我们可以找到视频的网址
2021-09-10
其中url1:https://vod10.bdzybf.com/20210818/sdtRN58R/index.m3u8是存放存放m3u8文件的文件的网址
我们用抓包工具可以看到这个网址的response是
2021-09-10
第三行就是真正存放m3u8文件的网址

抓取视频分析2

我们可以发现这个网址和url1仅仅差了/1000kb/hls
我们请求到url2:https://vod10.bdzybf.com/20210818/sdtRN58R/1000kb/hls/index.m3u8
在response里面可以看到
2021-09-10
其中第六行的METHOD是ts文件的解密方法,
URI是密匙网址,(我们需要拼接一下正确的网址)
每一行没有以#开头的就是ts文件的下载路径(同样需要拼接处理)

密匙

访问密匙网址,response是
2021-09-10
这16位就是密匙

思路

由前面的文件等等我们最终会得到一些未解密的ts文件
而我们需要的是视频,所以我们需要解密合并

我们需要导入
2021-09-10

开始爬虫

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循环即可

2021-09-10

上一篇:CVPR2017:深度纹理编码网络 (Deep TEN: Texture Encoding Network)


下一篇:力扣 155. 最小栈