python爬取视频

最近出了部新剧《一念关山》,觉得挺好看,就用python爬了一下这部剧,下面是完整代码~

注意:

1.博主python版本是3.11
2.使用的库都在下面有说明了

"""
爬取视频流程:
    1.拿到页面源码
    2.分析页面,是从接口处拿到m3u8(m3u)的url
    3.下载m3u8
    4.读取m3u8文件,下载视频
    5.下载密钥,进行解密
    5.合并视频
注意:
1.要先拿到源码,分析出m3u8地址,看看是否在源码还是接口处获取
2.通过m3u8拿到具体视频地址,要注意,有的平台会有两层m3u8,要注意甄别,一般正确的m3u8文件会很长
3.拿到地址异步下载视频
4.查看m3u8文件是否包含密钥,如果有要拿到密钥地址,获取密钥,然后解密视频
5.解密之后的密钥再来合并视频,合并视频有两种方法
--5.1 通过os合并,具体方法见下面代码,需要注意的是,超过300个.ts文件文件会合并失败
--5.2 这种方法直接写入文件,具体见下面代码,可以合并大量文件
注意:
    基本上所有的视频内容都包含在m3u8文件中,下载其中的内容合并就可以了
m3u8文件例子:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:18
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="enc.key",IV=0x00000000000000000000000000000000
#EXTINF:10.416667,
https://xxx/hls/141/20231016/1969067/plist0.ts
#EXTINF:10.958333,
https://xxx/hls/141/20231016/1969067/plist1.ts
...多个结构
#EXTINF:9.958333,
https://xxx/hls/141/20231016/1969067/plist239.ts
#EXT-X-ENDLIST
"""

import requests
import re
import asyncio
import aiohttp
import aiofiles
# 导入解密相关包  只需下载 pycryptodome即可
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes

import os

def get_m3u8(url): # 获取m3u8地址
    resp = requests.get(url)
    # print(resp.text)
    pat = re.compile(r'now="(?P<m3u8>.*?)";', re.S) # 获取m3u8地址
    m3u8 = pat.search(resp.text).group('m3u8')
    resp.close()
    # print(m3u8)
    resp1 = requests.get(m3u8) # 通过地址获取到m3u8内容
    # print(resp1.content)
    with open('video/m3u8.txt', mode='wb') as f:
        f.write(resp1.content) # 将m3u8内容保存到文件
    return m3u8 # 返回m3u8地址,备用

async def download_video(url,session): # 异步下载视频
    async with session.get(url) as resp: # 下载视频,下载完毕自动关闭
        async with aiofiles.open(f"video/{url.rsplit('/')[-1]}", mode='wb') as f: # 写入下载视频内容
            await f.write(await resp.content.read()) # 把下载内容写入文件(异步)
    print(f"{url.rsplit('/')[-1]}下载完毕")

async def get_video(): # 添加下载视频任务
    tasks = []
    async with aiohttp.ClientSession() as session:
        async with aiofiles.open('video/m3u8.txt', mode='r', encoding='utf-8') as f: # 读取url地址
            async for line in f:
                if line.startswith('#'): # 判断是否是url
                    continue
                line = line.strip() # 去掉没用的空格和换行
                task = asyncio.create_task(download_video(line, session)) # 创建下载视频任务
                tasks.append(task) # 添加到任务队列
            await asyncio.wait(tasks) # 等待任务结束

def get_key(url): # 获取key,进行视频解密
    return requests.get(url).text

async def excute_decrype(key): # 添加异步解密视频任务
    tasks = []
    async with aiofiles.open(f'video/m3u8.txt', mode='r', encoding='utf-8') as f:
        async for line in f:
            if line.startswith('#'):
                continue
            # 传入key和文件名
            name = line.rsplit('/')[-1].strip()
            task = asyncio.create_task(change_video(key, name))
            tasks.append(task)
        await asyncio.wait(tasks)

async def change_video(key, name): # 传入key和文件名称,解压视频
    # 使用CBC模式和随机生成的IV
    iv = get_random_bytes(16)
    cipher = AES.new(key.encode(), AES.MODE_CBC, iv) # 创建对象
    # 打开要解压的视频 video/{name},并同时创建解压后的视频文件 video/temp_{name}
    # \ 表示换行连接符,上下两行为一行
    async with aiofiles.open(f"video/{name}", mode='rb') as f1, \
        aiofiles.open(f"video/temp_{name}", mode='wb') as f2:
            bs = await f1.read() # 从源文件读取内容
            plaintext = unpad(cipher.decrypt(bs), AES.block_size) # 解密内容
            await f2.write(plaintext) # 把解密好的内容写入文件
    print(f"{name}写入成功")

def merge_video_ts():
    # 第一种合并方法:适用于不超过300个文件合并。
    # mac: cat 1.ts 2.ts 3.ts > xxx.mp4
    # windows: copy /b 1.ts+2.ts+3.ts xxx.mp4

    # video_list = []
    # with open('video/m3u8.txt', mode='r', encoding='utf-8') as f:
    #     for line in f:
    #         if line.startswith('#'):
    #             continue
    #         line = line.rsplit('/')[-1].strip()
    #         video_list.append(f'video/temp_{line}')
    # s = '+'.join(video_list)
    # os.system(f"copy /b {s} 'movie.mp4'")

    # 第二种方法;适用于大量文件合并
    with open("video/video.mp4", "wb") as f:
        with open("video/m3u8.txt", "r") as f1:
            for line in f1:
                if line.startswith("#"):
                    continue
                line = line.rsplit('/')[-1].strip()
                with open(f'video/temp_{line}', "rb") as f2:
                    f.write(f2.read())

    print('合并完成')

def main(url): # 主执行函数
    # 1.获取m3u8地址,并保存下载保持到文件
    m3u8 = get_m3u8(url)

    # 2.下载视频
    asyncio.run(get_video()) # 这里一定要用asyncio.run()包裹执行函数

    # 3.获取key值
    key = ''
    with open('video/m3u8.txt', mode='r', encoding='utf-8') as f:
        for item in f:
            # print(111,item)
            if('EXT-X-KEY' in item):
                # 获取m3u8中的key值
                pat = re.compile(r'URI="(?P<key>.*?)"', re.S).search(item).group('key')
                # 拼接key值,获取真正的获取Key的地址
                key_url = m3u8.replace('index.m3u8', pat) # 获取到得到key的地址
                key = get_key(key_url).strip() # 通过地址请求到key

    # 4.通过key解密视频
    asyncio.run(excute_decrype(key)) # 传入key,开始解压

    # 5.合并视频
    merge_video_ts()

if __name__ == '__main__':
    # 爬取xxx电影网 一念关山电视剧第一集
    url = 'https://xxxxxxx/play/106321-0-0.html'
    main(url) # 传入要获取的地址
    print('全部下载完成')

最后会得到一个video.mp4文件,这个就是最终文件了
在这里插入图片描述

到这里就可以观看视频了,有问题的可以留言~

Python爬取视频通常指的是从网页上下载视频文件到本地的过程。Python提供了很多库可以帮助完成这项任务,比如`requests`库可以用来发送网络请求,获取网页内容;`BeautifulSoup`或`lxml`等解析库可以用来解析网页内容;`youtube-dl`是一个专门用来下载YouTube等网站视频的命令行程序,也支持Python使用。 这里以`requests`和`BeautifulSoup`为例,简述一个基本的视频爬取流程: 1. 使用`requests`库发送GET请求获取目标网页内容。 2. 分析网页结构,确定视频资源的URL。 3. 如果视频资源是通过JavaScript动态加载的,可能需要使用`Selenium`等工具来模拟浏览器行为。 4. 使用`requests`库获取视频文件的二进制内容。 5. 将获取的视频内容写入文件。 下面是一个简化的代码示例: ```python import requests from bs4 import BeautifulSoup # 目标网页URL url = 'http://example.com/video-page.html' # 发送GET请求 response = requests.get(url) # 解析网页内容 soup = BeautifulSoup(response.text, 'html.parser') # 假设视频文件是通过<video>标签嵌入的 video_tag = soup.find('video') # 获取视频的真实地址,可能需要进一步解析 video_url = video_tag['src'] # 发送请求获取视频内容 video_response = requests.get(video_url, stream=True) # 确保请求成功 video_response.raise_for_status() # 写入文件 with open('video.mp4', 'wb') as file: for chunk in video_response.iter_content(chunk_size=1024): if chunk: # 过滤掉保持连接的新块 file.write(chunk) ``` 需要注意的是,爬取视频应遵守相关网站的服务条款和版权法规。一些网站明确禁止未经授权的视频下载,因此在进行爬取之前,应仔细检查网站的robots.txt文件和版权声明。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值