首页 > 其他分享 >Day 19 19.2 asyncio方法协程下载视频

Day 19 19.2 asyncio方法协程下载视频

时间:2023-03-24 18:23:02浏览次数:71  
标签:协程 19.2 m3u8 19 text ts url https import

视频文件下载

视频网址:https://www.9tata.cc/play/96891-0-0.html

一、单集视频下载

分析思路

  • 1、分析目标网址:有无反爬、是否需要逆向、存储视频文件的包的位置

  • 2、一般的视频文件。都是由一个个的ts文件组成,我们看到的整集视频,是由一个个小片段组合而成

  • 3、分析得到我们想要的存放ts文件的包即可下载我们想要的片段

  • 4、整合所有片段

第一步:确认网址

  • 首先打开网址,并进入,可以看到正常访问

第二步:打开开发者工具抓包

  • 定位到当前页面的响应数据返回的数据包

  • 重点关注“ .m3u8 ” 结尾的文件

1、第一个“ index.m3u8 ”文件

  • 我们可以发现其响应数据被重新定向

2、第二个“ index.m3u8 ”文件

  • 我们发现其相应数据中存储着内容,留意其中的内容,方便下一步分析

3、第三个“ FA0EEF118EB32F0BAFDDEA715476C39C.m3u8 ”文件

  • 我们可以发现其响应数据中存储的正是我们想要的一个个ts文件,但是我们需要想办法将其下载下来。

第三步、分析抓到的这几个“ .m3u8 ” 结尾的文件包

  • 对比三个文件的请求头

1、第一个文件

  • 请求数据:
    请求网址: https://c2.monidai.com/20230302/YXXKaX4f/index.m3u8
    状态代码: 302
    
    location: https://h0.rzisytn.cn/20230302/YXXKaX4f/index.m3u8
    
    响应数据:
    无法加载响应数据:没有可显示的内容,因为此请求被重定向了
    

2、第二个文件

  • 请求数据:
    请求网址: https://h0.rzisytn.cn/20230302/YXXKaX4f/index.m3u8
    状态代码: 200 OK
    
    响应数据:
    #EXTM3U
    #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1000000,RESOLUTION=1280x532
    /ppvod/FA0EEF118EB32F0BAFDDEA715476C39C.m3u8
    
    

3、第三个文件

  • 请求数据:
    请求网址: https://h0.rzisytn.cn/ppvod/FA0EEF118EB32F0BAFDDEA715476C39C.m3u8
    状态代码: 200 OK
    
    响应数据:
    #EXTM3U
    #EXT-X-VERSION:3
    #EXT-X-TARGETDURATION:10
    #EXT-X-MEDIA-SEQUENCE:0
    #EXTINF:6.8,
    /20230302/YXXKaX4f/1000kb/hls/CvBp8uD4551000.ts
    #EXTINF:2.04,
    /20230302/YXXKaX4f/1000kb/hls/CvBp8uD4551001.ts
    #EXTINF:9.32,
    .........
    

4、随机抓一个ts文件

  • 请求数据:
    请求网址: https://h0.rzisytn.cn/20230302/YXXKaX4f/1000kb/hls/CvBp8uD4551000.ts
    状态代码: 200 OK
    
    响应数据:
    一堆乱码,我们看不懂(因为视频是二进制数据)
    

第四步、比较分析

1、请求头及响应数据信息

第一个文件
请求网址: https://c2.monidai.com/20230302/YXXKaX4f/index.m3u8
状态代码: 302

location: https://h0.rzisytn.cn/20230302/YXXKaX4f/index.m3u8

第二个文件
请求数据:
请求网址: https://h0.rzisytn.cn/20230302/YXXKaX4f/index.m3u8
状态代码: 200 OK

响应数据:
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1000000,RESOLUTION=1280x532
/ppvod/FA0EEF118EB32F0BAFDDEA715476C39C.m3u8

第三个文件
请求数据:
请求网址: https://h0.rzisytn.cn/ppvod/FA0EEF118EB32F0BAFDDEA715476C39C.m3u8
状态代码: 200 OK

响应数据:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:6.8,
/20230302/YXXKaX4f/1000kb/hls/CvBp8uD4551000.ts

随机ts文件
请求数据:
请求网址: https://h0.rzisytn.cn/20230302/YXXKaX4f/1000kb/hls/CvBp8uD4551000.ts
状态代码: 200 OK

响应数据:
一堆乱码,我们看不懂(因为视频是二进制数据)

2、分析1

  • 第一个文件的状态码:302,以及其响应数据1展示的内容,即可了解到,其请求被重新定向,因此我们需要重新请求定向网址。

    • 定向的目标网址就是我们第二个文件的网址

    • 因此我们对第二个网址发起请求,获取响应数据2

3 、分析2

  • 我们从响应数据1和我们的第三个网址对比发现,其响应数据的最后一部分正是我们下一个文件的请求网址的一部分,我们将其提取出来,并发起请求,得到响应数据3

4、分析3

  • 我们从响应数据3,分析可看到我们的响应数据中包含的ts文件后缀名,正是我们每一个小文件的组成部分。因此我们对其发起请求,得到一个个小部分

5、得到目标数据,解析并存储

五、补充:

  • 1、第一个 m3u8 文件一定不是凭空出现,一定是基于该网页请求得到的响应数据。事实也是如此

  • 2、我们将第一个文件的网址复制,并在网页得到的响应数据页面进行搜索,就可以发现我们的请求网址,正是网页响应数据的一部分。

  • 3、从这里我们也可以看到,下一页的请求url我们也能得到,通过对第一页数据的解析过程,我们可以得到第二页的数据。方法是相通的。

  • 4、对于视频的合并,可以自行网上查找相关的工具或教程,也可通过代码实现。

六、单集视频文件下载代码:

import requests
import os
import time
from lxml import etree
import re
from fake_useragent import UserAgent
import asyncio
import aiohttp

# 去除ssl验证报错语句
requests.packages.urllib3.disable_warnings()
# UA 伪装
fake_ua = UserAgent()
headers = {
    'User-Agent': fake_ua.random
}
#创建session对象
session = requests.Session()

#该部分用来获得每一个ts文件的请求地址
async def get_every_ts_urls():
    #os方法创建文件夹
    filename = "movie"
    if not os.path.exists(filename):
        os.mkdir(filename)
    #对第二个文件发起请求获得响应书(已经被第一个文件重定向的url)
    first_url = 'https://h0.rzisytn.cn/20230302/YXXKaX4f/index.m3u8'
    #协程发起请求的固定方式
    async with aiohttp.ClientSession() as session:
        async with session.get(first_url, headers=headers, ssl=False) as response:
            page_text = await response.text()
            # /ppvod/FA0EEF118EB32F0BAFDDEA715476C39C.m3u8
            #解析并获得第三个文件所在的url
            index1_url = 'https://h0.rzisytn.cn' + page_text.split('\n')[2]
            #发起请求并做解析
            async with aiohttp.ClientSession() as session:
                async with session.get(index1_url, headers=headers, ssl=False) as response:
                    page_text = await response.text()
                    #得到每一个ts文件的网址
                    every_ts_urls = re.findall(r'\n(.*?\.ts)\n', page_text)
                    #存放所有url的列表
                    ts_list = []
                    #对每一个ts文件进行补充,使其成为完整的URL
                    for t in every_ts_urls:
                        url = 'https://h0.rzisytn.cn' + t
                        #添加到列表中
                        ts_list.append(url)
    #返回所有ts文件所在的列表
    return ts_list,url

#该部分用来解析并存储所有的ts文件
async def download_ts(url):
    #对每一个ts文件发起请求
    async with aiohttp.ClientSession() as session:
        async with session.get(url, headers=headers, ssl=False) as response:
            #获得响应数据:注意这里是二进制文件,所以不能text
            data = await response.read()
            title = os.path.basename(url)
            #定义文件路径
            filepath = os.path.join("movie", title)
            #利用try方法防止报错
            try:
                with open(filepath, 'wb') as f:
                    f.write(data)
                    f.close()
                print(f'{title}已下载完成')
            #若发生错误则报错
            except Exception as e:
                print(e)



async def main():
    start_time = time.time()
    # 获取到url列表
    ts_list,url = await get_every_ts_urls()
    #得到每一个ts文件的名字
    name = url.os.path.basename(url)
    #创建任务列表存放任务
    tasks = []
    #循环获得每一个url
    for url in ts_list:
        #创建并提交协程任务
        t = asyncio.create_task(download_ts(url))
        tasks.append(t)
    #收集 任务
    await asyncio.wait(tasks)

    print(f'总耗时为{time.time() - start_time}s')


if __name__ == '__main__':
    #运行任务
    asyncio.run(main())

七、纠正

对于单文件下方法中关于提取到所有ts文件url步骤的问题,上面的过于繁琐,且不好找

友情提醒:对数据不满意就多试试!有时候真的出人意料!

1·、请求视频页数据

2、分析响应数据

  • 在单文件中提到获取到 m3u8 文件地址的方法

  • 在这里我们获得视频页的响应数据,对其进行xpath方法,取到第一个文件的网址

    • import requests
      import os
      from lxml import etree
      import re
      from fake_useragent import UserAgent
      # 去除ssl验证报错语句
      requests.packages.urllib3.disable_warnings()
      # UA 伪装
      fake_ua = UserAgent()
      headers = {
          'User-Agent': fake_ua.random
      }
      session = requests.Session()
      
      def get_third_index():
          first_url = 'https://www.9tata.cc/play/96891-0-0.html'
          response = session.get(first_url, headers=headers, verify=False)
          response.encoding = 'utf8'
          page_text = response.text
      	#利用正则找到我们下一个地址的url(第一个文件对应的URL)
          first_link = re.findall(r'now="(.*?m3u8)"', page_text)[0]
          
          
          # 这是我们想要的URL:https://c2.monidai.com/20230302/YXXKaX4f/index.m3u8
      
  • 接着我们对提取到的该网址进行二次请求,得到响应数据

    • import requests
      import os
      from lxml import etree
      import re
      from fake_useragent import UserAgent
      
      # 去除ssl验证报错语句
      requests.packages.urllib3.disable_warnings()
      # UA 伪装
      fake_ua = UserAgent()
      headers = {
          'User-Agent': fake_ua.random
      }
      session = requests.Session()
      
      
      def get_third_index():
          first_url = 'https://www.9tata.cc/play/96891-0-0.html'
          response = session.get(first_url, headers=headers, verify=False)
          response.encoding = 'utf8'
          page_text = response.text
          first_link = re.findall(r'now="(.*?m3u8)"', page_text)[0]
          # https://c2.monidai.com/20230302/YXXKaX4f/index.m3u8
          response = session.get(first_link, headers=headers, verify=False)
          response.encoding = 'utf8'
          page_text = response.text
          # 这里打印的是获得到的响应数据
          print(page_text)
          # #EXTM3U
          # #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1000000,RESOLUTION=1280x532
          # /ppvod/FA0EEF118EB32F0BAFDDEA715476C39C.m3u8
      
          second_url = page_text.split('\n')[2]
          # 这正是我们想要的第三个文件对应的URL:https://h0.rzisytn.cn/ppvod/FA0EEF118EB32F0BAFDDEA715476C39C.m3u8
      
      
      if __name__ == '__main__':
          get_third_index()
      
      
  • 获得到的响应数据如下:

    •     # #EXTM3U
          # #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1000000,RESOLUTION=1280x532
          # /ppvod/FA0EEF118EB32F0BAFDDEA715476C39C.m3u8
      
  • 通过这里我们可以发现这正是我们第三个文件所对应的URL地址

https://h0.rzisytn.cn/ppvod/FA0EEF118EB32F0BAFDDEA715476C39C.m3u8

八、改良单集视频文件下载代码:

import requests
import os
import time
from lxml import etree
import re
from fake_useragent import UserAgent
import asyncio
import aiohttp

# 去除ssl验证报错语句
requests.packages.urllib3.disable_warnings()
# UA 伪装
fake_ua = UserAgent()
headers = {
    'User-Agent': fake_ua.random
}
session = requests.Session()


async def get_every_ts_urls():
    filename = "movie"
    if not os.path.exists(filename):
        os.mkdir(filename)
    # 视频页的url
    first_page_url = 'https://www.9tata.cc/play/96891-0-0.html'
    # 对视频页的url发起请求
    async with aiohttp.ClientSession() as session:
        async with session.get(first_page_url, headers=headers, ssl=False) as response:
            # 获取响应数据
            page_text = await response.text()
            # 每一集的名字
            name = re.findall(r'<td class="col2 hidden-xs">(?P<name>\w+)</td>', page_text)[0]
            print(f'当前视频是{name}')
            # 第一个m3u8的地址
            first_link = re.findall(r'now="(.*?m3u8)"', page_text)[0]
            async with aiohttp.ClientSession() as session:
                async with session.get(first_link, headers=headers, ssl=False) as response:
                    page_text = await response.text()
                    # 存放ts文件地址的url
                    # https://h0.rzisytn.cn/ppvod/FA0EEF118EB32F0BAFDDEA715476C39C.m3u8
                    second_url = 'https://h0.rzisytn.cn' + page_text.split('\n')[2]
                    async with aiohttp.ClientSession() as session:
                        async with session.get(second_url, headers=headers, ssl=False) as response:
                            page_text = await response.text()
                            # 提取出文件中每一个ts文件地址的后缀
                            every_ts_urls = re.findall(r'\n(.*?\.ts)\n', page_text)
                            ts_list = []
                            # 拼接url
                            for t in every_ts_urls:
                                url = 'https://h0.rzisytn.cn' + t
                                ts_list.append(url)
    return ts_list, name


async def download_ts(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url, headers=headers, ssl=False) as response:
            data = await response.read()
            title = os.path.basename(url)
            filepath = os.path.join("movie", title)
            try:
                with open(filepath, 'wb') as f:
                    f.write(data)
                    f.close()
                print(f'{title}已下载完成')
            except Exception as e:
                print(e)


def merge(filename='output'):
    '''
    视频合并
    :param filetime:
    :return:
    '''
    # 进入到下载目录
    os.chdir("movie")
    # 视频合并的命令
    os.system(f'ffmpeg -i index.m3u8 -c copy {filename}.mp4')
    print(f'{filename} -----合并成功!-----')


async def main():
    start_time = time.time()
    # 获取到url列表
    ts_list, name = await get_every_ts_urls()
    tasks = []
    for url in ts_list:
        t = asyncio.create_task(download_ts(url))
        tasks.append(t)
    await asyncio.wait(tasks)
    # merge(name)   #合并视频文件方法,需要配置相关程序,若无则注释掉

    print(f'总耗时为{time.time() - start_time}s')


if __name__ == '__main__':
    asyncio.run(main())

标签:协程,19.2,m3u8,19,text,ts,url,https,import
From: https://www.cnblogs.com/dream-ze/p/17252989.html

相关文章

  • HNCPC2019
    全1子矩阵分析:扩范围,到最后看面积是否等于1的个数实现:intT;intsum;intn,m;charg[N][N];voidsolve(){sum=0;for(inti=1;i<=n;i++)......
  • Centos7-tar包自定义安装mysql -ERROR 2002_ERROR 1045_ERROR 1054_ERROR 1290_ERROR
    @目录1.自定义安装mysql参考链接ERROR2002/ERROR1045/ERROR1054/ERROR12901.1、ERROR2002报错解决方法:1.2、ERROR1045报错解决方法:2.关于登录mys......
  • python gevnt实现协程
    gevent也是第三方库,自行调度协程,自动试别程序的耗时操作。比如读文件,等待时间。代码举了个栗子fromgeventimportmonkeymonkey.patch_all()importtimeimportgev......
  • CSP20230319-4 星际网络II 题解
    〇、题目题目描述随着星际网络的进一步建设和规模的增大,一个新的问题出现在网络工程师面前——地址空间不够用了!原来,星际网络采用了传统的IPv6协议,虽然有\(2^{128}\)级......
  • 最完美LTSC2021_19044.2788软件选装纯净版VIP40.0
    【系统简介】=============================================================1.本次更新母盘来LTSC2021.19044.2788。进一步优化调整。2.此版本精简量不大,满足各大平台需求......
  • Windows 10 1909 (Updated 2020-01-23)
    Windows10商业版(含教育版、企业版、专业版、专业教育版、专业工作站版)SHA1:67F9C7D6EC42CB1257697516F134799E020DE8E3ed2k://|file|cn_windows_10_business_editions_......
  • Windows 10 1909 (Updated 2019-12-17)
    Windows10商业版(含教育版、企业版、专业版、专业教育版、专业工作站版)SHA1:ee016317989ca607d786baa269fef756ebae9664ed2k://|file|cn_windows_10_business_editions_......
  • Windows 10 2004 (Updated 2020-05-12 v19041.208)
    Windows10商业版(含教育版、企业版、专业版、专业教育版、专业工作站版)SHA1:ED65CC6F3B4F90FDBDAB949BA6286708E8DCF0F1ed2k://|file|cn_windows_10_business_editions_......
  • Windows 10 2004 (Updated 2020-07-24 v19041.388)
    Windows10商业版(含教育版、企业版、专业版、专业教育版、专业工作站版)SHA1:77C83FF5329A5685649DA8A2D0936C045A0B25CAed2k://|file|cn_windows_10_business_editions_......
  • 洛谷 P1967 货车运输
    P1967NOIP2013提高组]货车运输-洛谷|计算机科学教育新生态(luogu.com.cn)这个题目算是lca的稍微拓展吧。主要思考方向应该是很明显的。就是考虑一条路径上权值最......