我记得以前好像写过一次抖音去水印云函数代码,这次主要是利用云开发做了抖音视频和图集,快手视频和图集,以及小红书,本站视频去水印解析代码。无需第三方API,直接使用云函数JS实现。
先说一下抖音去水印吧,这个应该是最普遍的,基本上哪里都能看到,当然需求也应该是最多的。如何获取到抖音短视频或图集的链接就不说了,这里以获取到一个短视频或图集链接开始,例如:
https://v.douyin.com/iSMn612Y/
这是一个抖音图集链接,获取到图片后我们需要获取到链接的重定向地址,代码如下:
async getRedirectUrl(url) {
try {
console.log("开始获取重定向URL:", url);
const response = await this.curl(url, {
method: "GET",
dataType: "text",
followRedirect: false,
});
console.log("重定向响应状态码:", response.status);
console.log("重定向响应头:", response.headers);
const redirectUrl = response.headers.location || url;
console.log("最终重定向URL:", redirectUrl);
return redirectUrl;
} catch (error) {
console.error("获取重定向URL时出错:", error);
throw error;
}
}
这样我们会获取到图集的详细地址,如下:
https://www.iesdouyin.com/share/note/7413711897830116608/?from_ssr=1&did=MS4wLjABAAAA_ZRjnl9xURp2Nui6mSbdBZD-zKuxZ_4XCrORVrlZnOyHvVKSTMMbXZ7WEc7q938F&mid=7386529472516376593&ts=1729489810®ion=CN&share_sign=EZcWgkQkqoMwZxaIuvyxXW0TN2cWPoFVkJJ8ZkaxKZU-&tt_from=share_to&with_sec_did=1&from_aid=1128&titleType=title&utm_source=share_to&utm_medium=ios&activity_info=%7B%22social_share_time%22:%221729491670%22,%22social_author_id%22:%223971887811007315%22,%22social_share_id%22:%223971887811007315_1729491670%22,%22social_share_user_id%22:%223971887811007315%22%7D×tamp=1729491669&share_version=310700&u_code=43k49fd35049&iid=MS4wLjABAAAAnlTijq4kdbAmlGgBbFVcvoPYhMp5oMFVOQh6-bg_fGd-_GapZ0AE5mNge6ItbVJ8&utm_campaign=client_share&app=aweme&schema_type=37
挺长的,但是我们只需要两个参数就行了,一个是链接中的note然后就是后面的ID,其中note主要是为了区分短视频和图集的,然后重要的就是视频的ID,得到分类和ID后,就可以开始进行下一步了。
// 构造请求头
const headers = {
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1 Edg/122.0.0.0",
};
// 发送请求获取信息
const response = await this.curl(`https://www.iesdouyin.com/share/${isImage ? "note" : "video"}/${id}`, {
headers: headers,
dataType: "text",
});
这样视频或图集的信息就藏在这个响应中,但是数据很乱,只要找到需要的参数就行了。
// 解析响应数据
const pattern = /window\._ROUTER_DATA\s*=\s*(.*?)<\/script>/s;
const matches = response.data.match(pattern);
if (!matches || !matches[1]) {
return {
code: 201,
msg: "解析失败:无法匹配信息"
};
}
const info = JSON.parse(matches[1].trim());
console.log("info:", info);
return isImage ? this.parseImageData(info) : this.parseVideoData(info);
上述代码中可以得到原始数据,然后图片和视频的分别进行解析得到数据,如下:
// 解析视频数据
parseVideoData(videoInfo) {
const itemData = this.safeGet(videoInfo, 'loaderData.video_(id)/page.videoInfoRes.item_list.0', {});
// 尝试获取无水印视频链接
let videoUrl = this.getNoWatermarkVideoUrl(itemData);
return {
code: 200,
msg: "解析成功",
data: {
type: "video",
author: this.safeGet(itemData, 'author.nickname', ''),
uid: this.safeGet(itemData, 'author.unique_id', ''),
avatar: this.safeGet(itemData, 'author.avatar_medium.url_list.0', ''),
like: this.safeGet(itemData, 'statistics.digg_count', 0),
time: this.safeGet(itemData, 'create_time', ''),
title: this.safeGet(itemData, 'desc', ''),
cover: this.safeGet(itemData, 'video.cover.url_list.0', ''),
url: videoUrl,
music: {
author: this.safeGet(itemData, 'music.author', ''),
avatar: this.safeGet(itemData, 'music.cover_large.url_list.0', ''),
},
view_count: this.safeGet(itemData, 'statistics.play_count', 0),
share_count: this.safeGet(itemData, 'statistics.share_count', 0),
platform: "douyin",
},
};
}
// 尝试获取无水印视频链接
getNoWatermarkVideoUrl(itemData) {
let videoUrl = '';
// 方法1:尝试从 play_addr 中获取无水印链接
const playAddr = this.safeGet(itemData, 'video.play_addr', {});
videoUrl = this.safeGet(playAddr, 'url_list.0', '');
// 如果获取到的 URL 包含 "playwm",尝试将其替换为 "play"
if (videoUrl.includes('playwm')) {
videoUrl = videoUrl.replace('playwm', 'play');
}
// 方法2:如果上面的方法失败,尝试从 download_addr 获取
if (!videoUrl) {
const downloadAddr = this.safeGet(itemData, 'video.download_addr', {});
videoUrl = this.safeGet(downloadAddr, 'url_list.0', '');
}
// 方法3:如果还是失败,使用原始的 play_addr
if (!videoUrl) {
videoUrl = this.safeGet(itemData, 'video.play_addr.url_list.0', '');
}
return videoUrl;
}
上面是视频具体的解析方案,然后下面是图片的解析方案,
parseImageData(imageInfo) {
const noteData = this.safeGet(imageInfo, 'loaderData.note_(id)/page.videoInfoRes.item_list.0', null);
if (!noteData) {
return {
code: 404,
msg: "未找到图集信息"
};
}
const imageList = noteData.images || [];
return {
code: 200,
msg: "解析成功",
data: {
type: "image_set",
author: this.safeGet(noteData, 'author.nickname', ''),
uid: this.safeGet(noteData, 'author.unique_id', ''),
avatar: this.safeGet(noteData, 'author.avatar_medium.url_list.0', ''),
like_count: this.safeGet(noteData, 'statistics.digg_count', 0),
comment_count: this.safeGet(noteData, 'statistics.comment_count', 0),
time: noteData.create_time,
title: noteData.desc,
cover: this.safeGet(imageList, '0.url_list.0', ''),
images: imageList.map((img) => ({
url: this.safeGet(img, 'url_list.0', ''),
width: img.width,
height: img.height,
})),
view_count: this.safeGet(noteData, 'statistics.play_count', 0),
share_count: this.safeGet(noteData, 'statistics.share_count', 0),
platform: "douyin",
},
};
}
当然其实得到参数后你想怎么处理就怎么处理了,所以到这里就结束了。最后代码中safeGet是一个用于代码?.的函数,因为我测试node18支持,但是node12好像不支持?.。
// 安全获取对象属性
safeGet(obj, path, defaultValue = '') {
return path.split('.').reduce((acc, part) => {
if (acc && typeof acc === 'object' && part in acc) {
return acc[part];
}
return defaultValue;
}, obj);
}
大致就是这些了,明天在更新快手如何获取无水印视频及图集吧,有什么问题可以留言哦~
本文来自投稿,不代表本站立场,如若转载,请注明出处:https://www.i4qq.com/jpjc/dydspqsyyhskf.html