获取Youtube视频缩略图上的预览链接

5
在Youtube中,当鼠标悬停在视频缩略图上时,会开始播放一个短预览。仅适用于桌面设备。
我试图获取其中一个链接。
 https://i.ytimg.com/an_webp/d1w3CWfhzNQ/mqdefault_6s.webp?du=3000&sqp=CPyAhNIF&rs=AOn4CLBqWnVyWD9F_P4j_WFk7LAGs4pNUA

它仅适用于上述视频, 当我尝试更改链接中的id以查看另一个视频时,不起作用,那么我该如何获得一个依赖于id的视频预览链接?


有人可以帮忙吗!!! - Muhammad
它与sqp和rs参数有关。如何根据我目前拥有的videoID获取这些参数,我完全不知道。如果有人弄清楚了,请告诉我。图像示例:https://i.ytimg.com/an_webp/yzrRfyfNw9Y/mqdefault_6s.webp?du=3000&sqp=COCmjdQF&rs=AOn4CLCUTiLsD4d_JaGTa4SIViUP9SU45A - Michael d
我也不知道。 - Muhammad
我提供的图片示例已过期,现在显示为空白,就像你的一样。这让我想到谷歌定期更改这些URL。 - Michael d
2个回答

6
spq参数是经过base64编码的Protocol Bufffer数据。在这种情况下,它是一个具有字段号1的4字节数字。如果没有规范说明或更多关于返回文件的上下文或更多样本的信息,我无法告诉您这是什么类型的数字(浮点数、有符号整数、无符号)或者代表什么含义。
sqp参数同样用于自定义缩略图的URL。例如,https://i.ytimg.com/vi/jNQXAC9IVRw/hqdefault.jpg?sqp=-oaymwEXCPYBEIoBSFryq4qpAwkIARUAAIhCGAE=&rs=AOn4CLAb9wuXOpXrY3TDtPwmmgz4l9PQxg 指示服务器返回缩略图按比例缩放和裁剪以达到246x138的分辨率,这是搜索结果中缩略图所使用的分辨率。这个分辨率不在标准分辨率选择中可用,即:
https://i.ytimg.com/vi/[video id]/hqdefault.jpg
https://i.ytimg.com/vi/[video id]/mqdefault.jpg
https://i.ytimg.com/vi/[video id]/sddefault.jpg
https://i.ytimg.com/vi/[video id]/default.jpg

在这种情况下,sqp参数编码了数字138和246,另外还有一些数据,我不确定其用途。然而,它的数据始终是相同的。
rs参数也是base64编码数据(但不是protobuf)。该数据的前5个字节始终相同。剩余的20个字节可能是视频ID、sqp参数中的数据以及其他秘密数据的SHA-1散列值。我不知道这些数据是如何组合的,或者在制作哈希时是否使用了其他数据。如果更改视频ID和/或sqp参数,则哈希将无法通过服务器端检查,图像将不会被调整大小。取而代之的是,它会给你hqdefault.jpg图像,就好像你从未使用过sqp/rs参数。
这几乎肯定是故意保密的数据,所以你不能生成这些URL,以防止通过请求不同大小的图像来占用服务器资源并使其饱和的拒绝服务攻击。
长话短说,对于视频预览,很可能没有办法重现rs参数以获取你想要的链接,因为与缩略图不同,你似乎不能简单地省略参数。

3
我写了一个示例javascript函数,可以抓取视频的webp预览图。如果找到了预览图,则返回包含url的promise;如果未能找到预览图,则表示该视频无法提供预览,或是由于Youtube更改了其网站的html格式导致该函数不再起作用(这种情况在未来肯定会发生,因此如果您在您的网站上将此功能用于生产,请确保还要构建一个检查程序以周期性地验证该方法是否仍然有效。如果它停止工作了,可能只需要做出微小的更改即可让它重新运行)。

该promise大约在一秒钟后返回结果;因为有几点可能导致它未能返回预览图,所以请务必不要使您的网站UX依赖它总是返回预览图

更好的方法是在您的后端上运行代码,并将图像保存到后端。(但是我不确定这是否违反了Youtube的版权规定)

const youtubeAnimation = id => {
    return fetch(
        `https://cors-anywhere.herokuapp.com/https://www.youtube.com/results?search_query=${id}&sp=QgIIAQ%253D%253D`,
        { headers: {} }
    )
        .then(r => r.text())
        .then(html => {
            const found = html.match(
                new RegExp(`["|']https://i.ytimg.com/an_webp/${id}/(.*?)["|']`)
            );
            if (found) {
                try {
                    const url = JSON.parse(found[0]);
                    return url;
                } catch (e) {}
            }
            throw "not found";
        })
        .catch(e => {
            return false;
        });
};

示例调用:

youtubeAnimation('s86-Z-CbaHA').then(console.log)

解释:

  1. 以视频ID作为搜索关键字,获取实际的YouTube搜索结果页面。使用URL参数&sp=QgIIAQ%253D%253D来强制匹配查询。
  2. 我在Heroku上使用了一个常见的代理服务器来绕过CORS阻挡。这是必需的,才能在浏览器中运行该函数。
  3. 搜索整个HTML代码,查找我们要寻找的webp文件格式(包括我们的视频ID)。
  4. 如果找到,则将其解析为JSON格式(图像在HTML中的某个位置内部)。否则,返回false。

感谢 @Hacktisch ,你给了我最好的解决方法。 - Muhammad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接