【技术探索】使用 Tampermonkey 脚本下载在线视频
这篇博客记录了如何从零开始分析网页流媒体传输,利用 Tampermonkey 自建一个请求嗅探脚本,拦截请求并将视频分片保存到本地。内含完整 JS 脚本。
朋友想做一个体育球星的剪辑,托我帮忙下载几场赛事的直播回放。一开始我不以为意:直接去 Tampermonkey 搜索一下对应网站的下载脚本就可以了嘛。后来发现事情并没有这么简单——脚本站里基本找不到什么能用的工具,只好自己动手了。
⚠️ 重要提示与免责声明
本文所介绍的技术方法,其唯一目的是进行前端技术原理的探索与个人学习交流。请务必注意:
- 版权尊重:互联网上绝大多数视频内容均受版权法保护。未经版权方书面许可,下载、传播受保护的视频内容可能构成侵权行为。
- 合理使用:本文方法仅适用于无版权保护、明确允许下载或已获授权的个人学习素材。
- 责任自担:作者分享此技术思路,不代表鼓励或纵容滥用。因使用本文技术而产生的任何版权纠纷或法律后果,均由使用者自行承担。
前言#
把网站上视频下载下来,可以说是一个非常常见的需求了。但由于版权等诸多限制,绝大多数视频都没有提供下载的渠道。于是网友们就开始了八仙过海——通过各种手段解析到视频源,并直接从源头下载。慷慨的网友们还会把这些方法打包成工具,开箱即用,直接下载。
因此,我首先想到的也是寻找可以利用的工具。对于Web端的各类操作,最合适且强大的莫过于Tampermonkey。只需载入特定脚本,就能够随心所欲地操纵网页上的资源,网页上的视频同样也是如此。于是,我开始在脚本站 Greasy Fork ↗上按照关键词和域名寻找解决方案,也找到了几个适配的脚本。
但很遗憾,轮番尝试了好几个脚本,没有一个正常工作的。朋友又在催,只好硬着头皮上,试试看能不能手动获取视频资源了。
方法分析#
严格来说,只要是能够在浏览器中播放的媒体,其背后必然涉及到一个“请求并返回媒体数据”的过程,无一幸免。只要按 F12 打开浏览器开发者工具,在视频播放时观察“网络”选项卡,就能捕获这些数据传输的痕迹。
果然不难观察到,在播放时,浏览器持续在向服务器发起对 .ts 类型文件的请求,每次的传输量高达 7MB 以上。.ts 是一种传输流(Transport Stream)文件,常用于在网络上传输流媒体,视频通常会被拆成分片,依次传输。

在请求上单击右键,并在新标签页上打开,可以看到该请求直接触发了浏览器的下载。打开下载后的文件,可以正常播放,是一个长度为 10s 的切片——很幸运,这个网站并没有在传输过程中进行更多加解密操作。

继续对请求进行分析,可以看到不同分片的请求参数几乎一致,只有一个 encrypt 字段存在不同。这也就意味着,要想向服务器发送请求并得到返回结果,必须构造出正确的 encrypt 字段。它由32个字母或数字构成,但由于构造它的网站脚本是被混淆过的,逆向有一定难度,这次就不深入分析了。
这也就是说,我们没法通过构造请求的方式,批量下载视频分片并整合。但是,我们可以直接获取播放器已经构造好的请求,用它们获取对应的文件。体现在操作上无非是多了一步:完整播放一遍视频,让播放器缓冲每一个分片——如果想要节约时间,也可以倍速播放。
研究到这里,下载视频的大致思路就形成了:
- 使用 Tampermonkey 脚本监听网页请求,并筛选出其中对
.ts文件的请求,将其作为目标。 - 脚本触发浏览器的下载机制(脚本无法直接请求下载,会触发 CORS 限制),将分片下载到本地。
- 在本地使用 FFmpeg 将
.ts文件合并成 mp4 文件。
实战操作#
掌握了思路后,我使用 ChatGPT 直接生成了脚本代码:
// ==UserScript==
// @name TS Sniffer & Direct Downloader (miguvideo)
// @namespace https://video-ts-sniffer
// @version 0.2
// @description 监听 ts 请求并直接触发浏览器下载(绕过 CORS)
// @match https://www.***马赛克***.com/*
// @grant none
// ==/UserScript==
// Vibe Coding 真是太爽辣!!
(function () {
"use strict";
const downloaded = new Set();
// 判断请求是否为目标请求
function isTargetTS(url) {
try {
const u = new URL(url);
// console.log("[TS] 检测路径名:", u.pathname);
return (
u.hostname === "马赛克.vod.某某video.com" &&
u.pathname.endsWith(".ts")
);
} catch (e) {
return false;
}
}
// 返回请求文件名
function extractFileName(url) {
try {
const u = new URL(url);
return u.pathname.split("/").pop();
} catch (e) {
return "segment.ts";
}
}
// 触发下载
function triggerDirectDownload(url) {
if (downloaded.has(url)) return;
downloaded.add(url);
const filename = extractFileName(url);
console.log("[TS] 触发下载:", filename);
// 直接在页面上生成一个下载链接的标签,并模拟浏览器点击,触发下载
const a = document.createElement("a");
a.href = url;
a.download = filename;
a.rel = "noopener";
a.style.display = "none";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
// ---- Hook fetch ----
const origFetch = window.fetch;
window.fetch = function (...args) {
const url = args[0]?.toString?.() || "";
if (isTargetTS(url)) {
triggerDirectDownload(url);
}
return origFetch.apply(this, args);
};
// ---- Hook XMLHttpRequest ----
const origOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function (method, url, ...rest) {
this._ts_url = url;
return origOpen.call(this, method, url, ...rest);
};
const origSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function (...args) {
this.addEventListener("load", () => {
const url = this._ts_url;
if (isTargetTS(url)) {
triggerDirectDownload(url);
}
});
return origSend.apply(this, args);
};
console.log("[TS] Direct downloader 已启动");
})();javascript将代码加载到 Tampermonkey 并以倍速播放视频,后台便开始程序下载分片文件。分片请求并下载的速度取决于视频缓冲速度(网速)与倍速播放速度。关于倍速播放,也可以在 Tampermonkey 中加载相关的脚本。
下载完毕后,使用 FFmpeg 即可合并文件。为了便于操作,我将所有分片的文件名保存到了一个文档 file.txt 中,并在命令中调用这个文档。
ffmpeg -f concat -safe 0 -i file.txt -c copy final.mp4shell生成文件名时写了一个简易的 Python 脚本:
import glob
import re
files = sorted(glob.glob("*.ts"), key=lambda x: int(re.search(r'-(\d+)\.ts$', x).group(1)))
with open("file.txt","w",encoding="utf-8") as f:
for line in files:
f.write(f'file \'{line}\'\n')python在一番快速处理之后,整合后的文件就成功输出了。


结语#
最终也是成功交差了,没想到下载整合之后的视频足足有 3GB 之大,可见质量还是很高的。但如果需求是截取一小段作为剪辑素材,个人认为录屏会更加方便。
最后再对该方法的局限性作简要提醒:它仅适用于未经过复杂加密的流媒体传输(如明文传输的.ts分片)。而目前主流的付费视频平台(如Netflix、Disney+、国内主流长视频平台的高清/付费内容)普遍采用了 Widevine L1/L3、PlayReady 等商业级加密方案,视频内容本身就是密文,单纯拦截网络请求无法得到可直接播放的素材。破解此类加密已超出技术探索与个人学习的范畴,且存在极高的法律风险。