dztkdx 2021-11-06 19:58 采纳率: 30%
浏览 35
已结题

关于网页视频解析爬取以及合成的问题

实现功能:在爬取一个网站的视频
1、拿到主页面的页面源代码,找到iframe
2、从iframe页面源代码中拿到m3u8文件
3、下载第一层m3u8文件,拿到真实地址
4、下载视频
5、下载key(密钥),进行解密操作
6、合并所有ts文件为一个MP4文件
'''

目前基本确定是在第4步和第5步是有问题的,但不清楚是代码错误的原因,还是因为好像有几个分段视频没有下载完成引起的;
所以导致第6步的问题也不清楚是什么导致的;求老鸟

问题截图:

img

img

img

代码页

import requests
from bs4 import BeautifulSoup 
import re    
import asyncio
import aiohttp   
import aiofiles   
from Crypto.Cipher import AES 
import os   
 
#正则提取规则
obj1=re.compile(r'2.html","link_pre":"","url":"(?P<src>.*?)","url_next":"https:')
 
#2.1子程序:找到主页面的源代码,找到iframe对应的url
 
def get_iframe_src(url):
    resp=requests.get(url)
    #print(resp.text)  #测试是否正常爬取到源代码
 
 
    #修改为正则爬取,这里提取完之后就是第一层的m3u8地址了
    content=resp.text  #把源代码变成text格式存储起来,用来提取
    main_page=obj1.finditer(content)
    for it in main_page:
        #print(it.group('src'))  
        src_modify=it.group('src').replace('\\','')   
        #print(src_modify) 
        return src_modify  #输出正确的第一层m3u8地址
    resp.close()
 
  
 
 
#2.2、子程序:拿到第一层的m3u8文件下载地址;这一步只在课程里91看剧需要,实操的网址2.1里拿到的就是第一层m3u8了
def get_first_m3u8_url(url):
    resp=requests.get(url)
    #print(resp.text)
    obj2=re.compile(r'var main=''(?P<m3u8_url>.*?)''')
    m3u8_url=obj2.search(resp.text).group('m3u8_url')   #这里是把m3u8地址提取出来
    #print(m3u8_url)
    resp.close()
    return m3u8_url  #让函数返回这一个地址
 
 
#2.3、子程序:下载第一层m3u8文件
def download_m3u8_file(url,name):
    resp=requests.get(url)
    with open(name,mode='wb')as f:
        f.write(resp.content)
    resp.close()
 
 
 
#2.5.1、子程序:异步协程进行下载
async def download_ts(url,name,session):
    async with session.get(url)as resp:
        async with aiofiles.open(f'4.9-video2/{name}',mode='wb')as f:
            await f.write(await resp.content.read())  #把下载到的内容写入文件中
    print(f'{name}下载完毕')
 
 
#2.5、子程序:异步协程处理拼接下载
 
 
#实操版
async def aio_download(up_url):
    tasks=[]
 
   
    async with aiohttp.ClientSession() as session:
 
        async with aiofiles.open('4.93-抓取91看剧复杂版——second-m3u8.txt',mode='r',encoding='utf-8')as f:
            async for line in f:
                if line.startswith('#'):  #’#‘开头的行不要
                    continue
                # line就是xxxx.ts文件
                url = line.strip() 
                name1=line.rsplit('/',1)[1] 
                name=name1.strip()
                task=asyncio.create_task(download_ts(url,name,session))
                tasks.append(task)
            await asyncio.wait(tasks)  #等待任务结束
 
#2.6.1获取密钥
def get_key(url):
    resp=requests.get(url)
    print(resp.text)  
 
    a=resp.text
    b=bytes(a,'utf-8')  
 
    return b
 
#2.6.2创建解密视频的任务
async def aio_dec(key):
    #思路:解密,需要把下载的文件一个个打开;但是因为这里我们是直接用m3u8文件里后面的字符命名的
    tasks=[]
    async with aiofiles.open('4.93-抓取91看剧复杂版——second-m3u8.txt',mode='r',encoding='utf-8')as f:
        async for line in f:
            if line.startswith('#'):
                continue
            line1=line.rsplit('/',1)[1]  #取网址最后一个斜杠后面的字符作为文件名,意思是:从右边切,切一次,得到【1】的位置的内容
            line=line1.strip()
            #开始创建异步任务
            task=asyncio.create_task(dec_ts(line,key))
            tasks.append(task)
        await asyncio.wait(tasks)
 
#2.6.3创建解密函数
async def dec_ts(name,key):
    aes=AES.new(key=key,IV=b'0000000000000000',mode=AES.MODE_CBC)
    
    async with aiofiles.open(f'4.9-video2/{name}',mode='rb')as f1,\
        aiofiles.open(f'4.9-video2/temp_{name}',mode='wb')as f2:
        bs=await f1.read()  #从源文件读取文件
        await f2.write(aes.decrypt(bs))  #把解密好的内容写入文件
    print(f'{name}处理完毕')
 
#2.7合并视频为mp4
def merge_ts():
    #mac:cat 1.ts 2.ts 3.ts > xxx.mp4
    #windows:copy/b 1.ts+2.ts+3.ts > xxx.mp4
    lst=[]
    with open('4.93-抓取91看剧复杂版——second-m3u8.txt',mode='r',encoding='utf-8')as f:
        for line in f:
            if line.startswith('#'):
                continue
            line1 = line.rsplit('/', 1)[1]  # 取网址最后一个斜杠后面的字符作为文件名,意思是:从右边切,切一次,得到【1】的位置的内容
            line=line1.strip()
            lst.append(f'4.9-video2/temp_{line}')
    s=''.join(lst)
    os.system(f'copy /b {s} >movie.mp4')
    print('搞定!')
 
 
 
#2、主程序
def main(url):
    #2.1、找到主页面的源代码,找到iframe对应的url
    iframe_src=get_iframe_src(url)
    #print(iframe_src)
  
    #2.3下载第一层m3u8文件
    download_m3u8_file(iframe_src,'4.93-抓取91看剧复杂版——first-m3u8.txt')  #按照课程正常的话括号里的’iframe_src‘要改为2.2里的’first_m3u8_url_ture‘
    #2.4下载第二层m3u8文件
 
    with open('4.93-抓取91看剧复杂版——first-m3u8.txt',mode='r',encoding='utf-8') as f:
        for line in f:
            if line.startswith('#'):  #让程序识别文件里面时,自动跳过‘#’开头的行段
                continue
            else:
                line=line.strip()  #去掉空白或者换行符
                #准备拼接第二层m3u8的下载路径
                second_m3u8_url=iframe_src.split('/20210730')[0]+line
                download_m3u8_file(second_m3u8_url,'4.93-抓取91看剧复杂版——second-m3u8.txt')
                print('第二层m3u8下载完毕')
 
    #2.5下载视频
 
    #实操写法
    up_url='开始'
    #asyncio.run(aio_download(up_url))   #这个会报错:RuntimeError: Event loop is closed
    loop=asyncio.get_event_loop()     
    loop.run_until_complete(aio_download(up_url))    
 
    #2.6.1拿到密钥
    #实操
    key_url='https://ts6.hhmm0.com:9999/20210730/QoNAXIDD/1000kb/hls/key.key'  
 
    
    key=get_key(key_url)  #访问密匙的路径,拿到密匙
 
    #2.6.2解密
    asyncio.run(aio_dec(key))
 
    #2.7合并ts文件为mp4文件
    merge_ts()
 
#1、主程序调用处
if __name__=='__main__':
    url='https://www.pianba.net/yun/84961-1-1/'
    main(url)


  • 写回答

1条回答 默认 最新

  • 有问必答小助手 2021-11-08 10:13
    关注

    你好,我是有问必答小助手,非常抱歉,本次您提出的有问必答问题,技术专家团超时未为您做出解答


    本次提问扣除的有问必答次数,已经为您补发到账户,我们后续会持续优化,扩大我们的服务范围,为您带来更好地服务。

    评论

报告相同问题?

问题事件

  • 系统已结题 11月14日
  • 创建了问题 11月6日

悬赏问题

  • ¥15 ubuntu子系统密码忘记
  • ¥15 信号傅里叶变换在matlab上遇到的小问题请求帮助
  • ¥15 保护模式-系统加载-段寄存器
  • ¥15 电脑桌面设定一个区域禁止鼠标操作
  • ¥15 求NPF226060磁芯的详细资料
  • ¥15 使用R语言marginaleffects包进行边际效应图绘制
  • ¥20 usb设备兼容性问题
  • ¥15 错误(10048): “调用exui内部功能”库命令的参数“参数4”不能接受空数据。怎么解决啊
  • ¥15 安装svn网络有问题怎么办
  • ¥15 vue2登录调用后端接口如何实现