C# WinForm爬取小红书无水印视频:从笔记采集到FFmpeg转码实战

说到采集小红书无水印视频,很多人的第一反应是找现成的轮子。确实,市面上有像 XHS-Spider 这样的工具,颜值高、能批量下载,但有个坑——它基于 .NET 6.0 开发,而且从 v1.0.1.4 版本开始就不再开源,需要申请授权文件,授权时长只有一天 。

对于习惯了在 .NET Framework 4.8 下做 WinForm 桌面工具的老铁来说,这路子有点堵。

既然这样,不如自己造个轮子。核心思路拆开看就三板斧:

  1. 搞定笔记列表和详情接口,拿到视频直链;
  2. 把链接里的视频扒下来;
  3. 用 FFmpeg 转成网页兼容的 MP4(H.264/AAC)。

下面咱们就用 C# WinForm 4.8,把这个流程走一遍。

一、开局:HttpClient 模拟请求,绕过反爬

采集的第一步是模拟 App 或 Web 端的请求。小红书的接口校验比较严,Cookie 和 User-Agent 是关键,缺一个都可能直接给你返回 {'code': -100, 'msg': '非法请求'}

实战中,我习惯从浏览器 F12 的 Network 面板里扒一个完整的 Cookie 字符串。注意,xsec_tokenweb_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 对象,其中 playUrlurl 就是我们要的无水印直链(注意,部分链接带 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 绑定,适合做播放器,不适合做工具调用 。

推荐两种优雅的方案:

  1. FFMpegCore:虽然是 .NET Standard 库,但在 .NET Framework 4.8 上兼容性不错,API 非常 fluent(流式),用起来舒服 。
  2. 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 的逻辑大概是这个样子:

  1. 用户在文本框输入笔记链接或 ID。
  2. 后台线程调用 Fetch 获取数据。
  3. 提取 JSON 中的直链地址,用 WebClientHttpClientGetByteArrayAsync 下载视频到临时目录(注意文件名不要带特殊符号)。
  4. 调用 FFmpeg 转码,进度通过事件回调刷新 UI 进度条。
  5. 转码完成后,将文件移动到用户指定的目录,并提示完成。

如果不想手写 FFmpeg 命令,FFMpegCore 支持的链式写法非常人性化,比如需要缩放为 720p:.WithVideoFilters(filterOptions => filterOptions.Scale(VideoSize.Hd))

五、避坑指南:你可能遇到的三个现实问题

  1. Cookie 过期太频繁:小红书的风控策略很严格。某次我批量采集 50 条视频,跑到第 20 条时 IP 就被封了。解决方案是引入代理池,或者在请求头中随机切换 User-Agent 。
  2. 视频链接时效性:有些直链是 CDN 临时签名,有效期只有几分钟。下载要趁热,拿到链接后必须立刻下载,隔几分钟再请求可能就失效了 。
  3. H.265 转码慢:如果源视频是 H.265(HEVC),在旧电脑上用 CPU 软解转码会非常慢。可以尝试在 FFMpegArguments 中加 WithHardwareAcceleration(HardwareAccelerationDevice.Cuda)(前提是有 N 卡),否则就只能耐心等待。

说白了,这套方案的核心就是模拟请求拿链接 + 进程调用 FFmpeg。虽然不如现成的闭源工具一键到位,但胜在完全可控,想怎么魔改都行。

分享到:

本文链接:https://www.biyeyuanma.cn/post/162.html

猜你喜欢

随机文章
热门标签
图片名称

服务热线

加我微信

加我微信