说到采集小红书无水印视频,很多人的第一反应是找现成的轮子。确实,市面上有像 XHS-Spider 这样的工具,颜值高、能批量下载,但有个坑——它基于 .NET 6.0 开发,而且从 v1.0.1.4 版本开始就不再开源,需要申请授权文件,授权时长只有一天 。
对于习惯了在 .NET Framework 4.8 下做 WinForm 桌面工具的老铁来说,这路子有点堵。
既然这样,不如自己造个轮子。核心思路拆开看就三板斧:
- 搞定笔记列表和详情接口,拿到视频直链;
- 把链接里的视频扒下来;
- 用 FFmpeg 转成网页兼容的 MP4(H.264/AAC)。
下面咱们就用 C# WinForm 4.8,把这个流程走一遍。
一、开局:HttpClient 模拟请求,绕过反爬
采集的第一步是模拟 App 或 Web 端的请求。小红书的接口校验比较严,Cookie 和 User-Agent 是关键,缺一个都可能直接给你返回 {'code': -100, 'msg': '非法请求'}。
实战中,我习惯从浏览器 F12 的 Network 面板里扒一个完整的 Cookie 字符串。注意,xsec_token 和 web_session 这种动态参数必须带全。
下面的代码封装了一个简单的请求方法,用于获取笔记详情页的 HTML 或接口 JSON 数据:
using System;
using System.Net.Http;
using System.Threading.Tasks;
public class XiaoHongShuFetcher
{
private static readonly HttpClient client = new HttpClient();
static XiaoHongShuFetcher()
{
// 必须配置,模拟真实设备
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36");
// 从浏览器复制完整的 Cookie 字符串
client.DefaultRequestHeaders.Add("Cookie", "你的Cookie字符串; web_session=xxx; xsec_token=xxx");
}
public async Task<string> GetNoteDetailAsync(string noteId)
{
// 这个接口是 Web 端常用的详情接口,返回 JSON
string url = $"https://www.xiaohongshu.com/explore/{noteId}";
try
{
var response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
// 踩坑警告:如果返回 403 或 412,说明 Cookie 过期或者触发了风控
return string.Empty;
}
}
}
踩坑警告:HttpClient 不要用 using 包裹频繁创建,否则会耗尽端口。项目里建议单例模式或者静态全局使用 。
二、提取直链:HTML 解析与 JSON 脱壳
拿到 HTML 或者 JSON 数据后,怎么抠出视频地址?
老办法是用 HtmlAgilityPack 解析 DOM 结构,但现在的页面大多是 SSR 或者客户端渲染,直接解析 HTML 容易翻车。更稳的方式是拦截接口返回的 JSON 数据。
在 WinForm 中,我们通常嵌入 WebView2 或直接用 HttpClient 调用内部 API。以笔记详情接口为例,返回的 JSON 里通常嵌套着 video 对象,其中 playUrl 或 url 就是我们要的无水印直链(注意,部分链接带 watermark=1 参数,去掉即可)。
这里给一段伪代码逻辑,演示如何从 JSON 字符串中提取视频地址(推荐使用 Newtonsoft.Json 解析):
using Newtonsoft.Json.Linq;
public string ExtractVideoUrl(string jsonResponse)
{
try
{
JObject obj = JObject.Parse(jsonResponse);
// 注意:实际的 JSON Path 需要根据抓包结构确定,常见于 data.items[0].video.playUrl
string videoUrl = obj.SelectToken("data.items[0].video.playUrl")?.ToString();
// 如果是无水印版本,通常去掉 ?watermark=xxx 后缀
if (!string.IsNullOrEmpty(videoUrl) && videoUrl.Contains("watermark"))
{
videoUrl = videoUrl.Split('?')[0];
}
return videoUrl;
}
catch (Exception ex)
{
// 日志记录:解析失败,可能是接口变了
return null;
}
}
其实有个更省事的思路:直接用现成的开源轮子 XHS-Downloader 的思路,它完全开源,基于 Python Requests 实现,核心逻辑就是提取作品下载地址,参考它的 API 调用方式能省不少抓包时间 。
三、转码核心:FFmpeg 在 .NET 4.8 下的正确打开方式
拿到视频直链(通常是 .mp4 或 .mov 格式,编码可能是 H.265 或 VP9)后,直接播放可能会绿屏或提示不支持。必须统一转成 H.264 + AAC 的 MP4。
在 .NET Framework 4.8 下调用 FFmpeg,不建议用 FFmpeg.AutoGen,那个太底层,是 unsafe 绑定,适合做播放器,不适合做工具调用 。
推荐两种优雅的方案:
- FFMpegCore:虽然是 .NET Standard 库,但在 .NET Framework 4.8 上兼容性不错,API 非常 fluent(流式),用起来舒服 。
- xFFmpeg.NET:直接封装了进程调用,支持进度事件,适合 WinForm 里做进度条 。
这里采用 FFMpegCore 方案。首先通过 NuGet 安装包,然后指定 ffmpeg.exe 的路径。
using FFMpegCore;
using FFMpegCore.Extend;
using System;
public void ConvertToWebCompatible(string inputPath, string outputPath)
{
// 注意:需要提前将 ffmpeg.exe 放在程序根目录或配置环境变量
GlobalFFOptions.Configure(options => options.BinaryFolder = AppDomain.CurrentDomain.BaseDirectory);
try
{
FFMpegArguments
.FromFileInput(inputPath)
.OutputToFile(outputPath, false, options => options
.WithVideoCodec(VideoCodec.LibX264) // 指定 H.264 编码
.WithAudioCodec(AudioCodec.Aac) // 指定 AAC 音频
.WithConstantRateFactor(23) // CRF 质量控制,23 是画质与体积的平衡点
.WithFastStart() // 开启 faststart,网页端边下边播必备
)
.ProcessSynchronously(); // 同步等待完成,适合 WinForm 后台线程
Console.WriteLine("转码完成: " + outputPath);
}
catch (Exception ex)
{
// 这里经常会遇到 FFmpeg 未找到、路径有中文空格等问题
throw new Exception("转码翻车了,检查下 ffmpeg 路径和文件权限", ex);
}
}
速度提示:如果不做缩放,直接用原分辨率转码,速度取决于 CPU 或显卡。4.8 环境下用
ProcessSynchronously会阻塞 UI 线程,记得用Task.Run包裹。
四、WinForm 落地:从列表到本地的完整链路
把以上几块拼起来,WinForm 的逻辑大概是这个样子:
- 用户在文本框输入笔记链接或 ID。
- 后台线程调用
Fetch获取数据。 - 提取 JSON 中的直链地址,用
WebClient或HttpClient的GetByteArrayAsync下载视频到临时目录(注意文件名不要带特殊符号)。 - 调用 FFmpeg 转码,进度通过事件回调刷新 UI 进度条。
- 转码完成后,将文件移动到用户指定的目录,并提示完成。
如果不想手写 FFmpeg 命令,FFMpegCore 支持的链式写法非常人性化,比如需要缩放为 720p:.WithVideoFilters(filterOptions => filterOptions.Scale(VideoSize.Hd)) 。
五、避坑指南:你可能遇到的三个现实问题
- Cookie 过期太频繁:小红书的风控策略很严格。某次我批量采集 50 条视频,跑到第 20 条时 IP 就被封了。解决方案是引入代理池,或者在请求头中随机切换 User-Agent 。
- 视频链接时效性:有些直链是 CDN 临时签名,有效期只有几分钟。下载要趁热,拿到链接后必须立刻下载,隔几分钟再请求可能就失效了 。
- H.265 转码慢:如果源视频是 H.265(HEVC),在旧电脑上用 CPU 软解转码会非常慢。可以尝试在
FFMpegArguments中加WithHardwareAcceleration(HardwareAccelerationDevice.Cuda)(前提是有 N 卡),否则就只能耐心等待。
说白了,这套方案的核心就是模拟请求拿链接 + 进程调用 FFmpeg。虽然不如现成的闭源工具一键到位,但胜在完全可控,想怎么魔改都行。


