图集短视频去水印云函数开发实践——快手

昨天分享了抖音图集短视频云函数去水印解析的开发实践,今天来说说快手的图集短视频解析,其实原理都差不多,哦,对了昨天以这些案例开发的小程序还在审核就没有分享,今天分享出来给大家看看效果,我没有做下载处理,所以短视频下载的话需要复制链接到其他点下载,不过这都不是啥难点。主要是实现去水印的目的就行,仅做演示。柠檬去水印

首先还是获取一个快手短视频或者图集的链接,演示如下:

ruby 复制代码
https://v.kuaishou.com/dlyk1

然后传到后端,后端会获取到其重定向到地址,但是考虑到有可能会重定向几次,所以做了一些处理,代码如下:

javascript 复制代码
async getFinalRedirectUrl(url, maxRedirects = 5) {
    let currentUrl = url;
    let redirectCount = 0;


    while (redirectCount < maxRedirects) {
      try {
        const response = await this.curl(currentUrl, {
          method: "GET",
          dataType: "text",
          followRedirect: false,
        });


        if (response.headers.location) {
          currentUrl = new URL(response.headers.location, currentUrl).href;
          console.log(`重定向 ${redirectCount + 1}: ${currentUrl}`);
          redirectCount++;
        } else {
          // 没有更多重定向,返回当前URL
          return currentUrl;
        }
      } catch (error) {
        console.error(`重定向过程中出错 (${currentUrl}):`, error);
        throw error;
      }
    }


    console.warn(`达到最大重定向次数 (${maxRedirects})`);
    return currentUrl;
  }

获取到的原地址应该如下:

ruby 复制代码
https://v.m.chenzhongtech.com/fw/photo/3xnh6zqupyhfm5e?cc=share_copylink&followRefer=151&shareMethod=TOKEN&docId=9&kpn=KUAISHOU&subBiz=BROWSE_SLIDE_PHOTO&photoId=3xnh6zqupyhfm5e&shareId=18116220443971&shareToken=X44fHQnInAjW1py&shareResourceType=PHOTO_OTHER&userId=3xw7it7sxf6k7pe&shareType=1&et=1_i%2F2007717946053474769_scn0&shareMode=APP&efid=0&originShareId=18116220443971&appType=1&shareObjectId=5241064204127827041&shareUrlOpened=0&timestamp=1729591920122

研究域名可以得到其中的ID,也就是链接中的3xnh6zqupyhfm5e,然后进行下一步,构造移动版网页URL,如下:

makefile 复制代码
const headers = {
      "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1",
      Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
      "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
    };
const mobileUrl = `https://c.kuaishou.com/fw/photo/${photoId}`;


      // 发送请求获取信息
      const response = await this.curl(mobileUrl, {
        headers: this.headers,
        dataType: "text",
      });


      console.log("响应数据:", response)

最后就是得到响应后的处理了。

typescript 复制代码
parseContentInfo(html) {
    const jsonMatch = html.match(
      /<script>window\.INIT_STATE = (.*?)<\/script>/
    );
    if (!jsonMatch) return null;


    try {
      const initState = JSON.parse(jsonMatch[1]);


      // 找到包含内容信息的键
      const contentInfoKey = Object.keys(initState).find(
        (key) => key.startsWith("tusjoh") && (initState[key].photo || initState[key].atlas)
      );
      console.log("内容信息键:", contentInfoKey);


      if (!contentInfoKey) {
        console.error("无法找到内容信息");
        return null;
      }


      const contentInfo = initState[contentInfoKey];
      console.log("内容信息:", contentInfo);


      const isAtlas = !!contentInfo.atlas;
      const photoInfo = contentInfo.photo;
      const atlasInfo = contentInfo.atlas;


      const baseInfo = {
        type: isAtlas ? "image_set" : "video",
        author: photoInfo.userName,
        uid: photoInfo.userId,
        avatar: photoInfo.headUrls[0].url,
        like_count: photoInfo.likeCount,
        comment_count: photoInfo.commentCount,
        time: photoInfo.timestamp,
        title: photoInfo.caption,
        cover: photoInfo.coverUrls[0].url,
        view_count: photoInfo.viewCount,
        share_count: photoInfo.shareCount || 0,
        platform: "kuaishou",
      };


      if (isAtlas) {
        baseInfo.images = atlasInfo.list.map((path, index) => ({
          url: `https://${atlasInfo.cdn[0]}${path}`,
          width: atlasInfo.size[index].w,
          height: atlasInfo.size[index].h,
        }));
      } else {
        baseInfo.url = photoInfo.mainMvUrls[0].url;
        baseInfo.duration = photoInfo.duration;
      }


      return baseInfo;
    } catch (error) {
      console.error("解析JSON数据时出错:", error);
      return null;
    }
  }

快手的数据有一个点不懂,他有一个很长的键,所以我们需要找到它,然后在进行处理,代码中的contentInfoKey就是起到这个作用,不过以后会不会变就不知道了,主要是方法,变了以后再改就行了。

javascript 复制代码
// 找到包含内容信息的键
      const contentInfoKey = Object.keys(initState).find(
        (key) => key.startsWith("tusjoh") && (initState[key].photo || initState[key].atlas)
      );

以上就是今天的内容了,有什么不懂的留言问就行。