某网站视频爬取(day3)

视频网站的工作原理

用用户上传一个视频,并不会被一次性保存,而是经过下面这几步。

**编码:**编码成不同质量级别、分辨率的多个版本。

**分块:**每个版本的视频都会被分割成连续的小视频片段,通常只有几秒钟,这些小片段通常采用.ts格式,也就是MPEG传输流。

**创建清单文件:**网站会创建一个“播放列表”文件作为索引,清单文件会告知视频播放器.ts数据块的顺序,一般使用的是M3U8文件作为清单文件。

**通过 CDN 分发:**所有这些 .ts 数据块和 .m3u8 播放列表都会上传到内容分发网络 (CDN),该网络的服务器遍布全球。这确保了无论用户身在何处,都能快速交付。

抓取流程分析

  1. 找到m3u8文件。
  2. 通过m3u8下载所有ts文件。
  3. 合并ts文件。

爬取

手工测试

我选了一个视频网站进行爬取。——https://www.ssrfun.com

image-20250709143157935

先不写脚本,看看能不能找到.ts文件的下载链接。

通过XHR过滤和抓包,能找到index.m3u8mixed.m3u8

image-20250709143337420

先下载index.m3u8,存放了mixed.m3u8的地址。

image-20250709143528542

再下载mixed.m3u8,这回可以找到视频的.ts文件了。

image-20250709143556855

下载其中一个.ts,得到的是视频的一个片段。

image-20250709143706618

脚本爬取

分析一下脚本流程:

  1. 获得视频链接,在返回的html中,存在m3u8文件的链接。
  2. 获得m3u8文件(A),读取并下载另一个m3u8文件(B)。
  3. 获得文件B,并解析获得ts文件的链接。
  4. 下载并合并所有ts文件。

没有反爬、没有风控,还是很简单的。

image-20250709163057151

之后使用ffmpeg进行合并。

image-20250709162152669

顺带补了一下asyncio.runasyncio的事件循环的关系。

在python3.7之前,需要手动创建事件循环并运行一个协程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import asyncio

async def main():
print("Hello")
await asyncio.sleep(1)
print("World")

# --- 手动挡操作 ---

# 1. 获取(或创建)一个事件循环
loop = asyncio.get_event_loop()

try:
# 2. 命令循环运行一个任务直到它完成
loop.run_until_complete(main())
finally:
# 3. 手动关闭事件循环
loop.close()

而async.run相当于自动挡,封装好了步骤。

  1. 它会自动创建一个新的事件循环。

  2. 它会自动调用 loop.run_until_complete() 来运行你指定的协程。

  3. 它会自动处理所有后续的清理工作。

  4. 最后,它会自动关闭事件循环。