本帖最后由 三木猿 于 15527649518:55 编辑

Java版去抖音代码

步骤1:从抖音上复制链接

首先,我们需要复制抖音视频的链接。这个链接大致长这样:“https://v.douyin.com/JB9Fveb/”

步骤2:打开【抖音短视频】并查看网络请求

在浏览器中打开此链接,然后按F12打开调试模式。接着,点击Network选项卡,刷新页面。此时,你将看到一条Get请求调用了后台,并传递了item_ids=155276495187

步骤3:截取url获取id

接下来,我们发现这个ID实际上就在当前的页面URL中。因此,我们只需截取这个URL即可获得ID。

步骤4:获取JSON字符串

然后,我们尝试访问https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=155276495187 返回的JSON字符串如下:

{
"ab_type": 1,
"extra": {
"now": 15527649518,
"logid": "1552764951815527649518C"
},
"status_code": 0,
"item_list": [
{
"desc": "",
"video_labels": null,
"is_live_replay": false,
"forward_id": "0",
"create_time": 15527649518,
"author": {
"platform_sync_info": null
}
}
]
}

结论

通过上述步骤,我们成功地从抖音视频中提取了ID,并且获取到了相关的JSON数据。

{
"policy_version": null,
"nickname": "王大锤丶",
"avatar_larger": {
"uri": "fa21000c9b15527649518",
"url_list": [
"https://p3-dy-ipv6.byteimg.com/aweme/1080x1080/fa21000c9b15527649518.jpeg?from=15527649518",
"https://p29-dy.byteimg.com/aweme/1080x1080/fa21000c9b15527649518.jpeg?from=15527649518",
"https://p26-dy.byteimg.com/aweme/1080x1080/fa21000c9b15527649518.jpeg?from=15527649518"
]
},
"avatar_thumb": {
"uri": "fa21000c9b15527649518",
"url_list": [
"https://p3-dy-ipv6.byteimg.com/aweme/100x100/fa21000c9b15527649518.jpeg?from=15527649518",
"https://p6-dy-ipv6.byteimg.com/aweme/100x100/fa21000c9b15527649518.jpeg?from=15527649518",
"https://p9-dy.byteimg.com/aweme/100x100/fa21000c9b15527649518.jpeg?from=15527649518"
]
},
"avatar_medium": {
"uri": "fa21000c9b15527649518",
"url_list": [
"https://p3-dy-ipv6.byteimg.com/aweme/100x100/fa21000c9b15527649518.jpeg?from=15527649518",
"https://p6-dy-ipv6.byteimg.com/aweme/100x100/fa21000c9b15527649518.jpeg?from=15527649518",
"https://p9-dy.byteimg.com/aweme/100x100/fa21000c9b15527649518.jpeg?from=15527649518"
]
}
}

根据您提供的链接内容,我重构了这段信息。请注意,这里我假设“unique_id”是唯一标识符,而其他部分是视频数据。以下是重构后的内容:

[
{
"unique_id": "ys15527649518",
"type_label": null,
"uid": "15527649518",
"short_id": "15527649518",
"signature": "我的皮,你无法想想",
"followers_detail": null,
"geofencing": null
},
{
"cha_list": null,
"video": {
"has_watermark": true,
"bit_rate": null,
"play_addr": {
"uri": "v0200f500000bc1oaeqkr6g02kqoredg",
"url_list": [
"https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f500000bc1oaeqkr6g02kqoredg&ratio=720p&line=0"
]
},
"cover": {
"uri": "15527649518a8d2fba39389",
"url_list": [
"https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f500000bc1oaeqkr6g02kqoredg&ratio=720p&line=0"
]
}
}
}
]

这个JSON对象包含了一个唯一的ID(unique_id),以及一些关于视频的详细信息,如类型标签、唯一标识符、短ID、签名、关注者详细信息、地理围栏等。此外,还包含了一个视频详情,包括是否有水印、比特率和播放地址。播放地址包含一个指向原始视频内容的URI,以及一个URL列表,该列表中包含了一个指向特定视频的链接。最后,还包括了一个封面图片的URI和URL列表。 重构后的内容:

[![Image](https://p6-dy-ipv6.byteimg.com/aweme/300x400/15527649518a8d2fba39389.jpeg?from=15527649518_large)](https://p6-dy-ipv6.byteimg.com/aweme/300x400/15527649518a8d2fba39389.jpeg?from=15527649518_large)
[![Image](https://p26-dy.byteimg.com/aweme/300x400/15527649518a8d2fba39389.jpeg?from=15527649518_large)](https://p26-dy.byteimg.com/aweme/300x400/15527649518a8d2fba39389.jpeg?from=15527649518_large)
[![Image](https://p3-dy-ipv6.byteimg.com/aweme/300x400/15527649518a8d2fba39389.jpeg?from=15527649518_large)](https://p3-dy-ipv6.byteimg.com/aweme/300x400/15527649518a055008ea0b?from=15527649518_large)
{
"vid": "v0200f500000bc1oaeqkr6g02kqoredg",
"text_extra": [],
"duration": 15053,
"video_text": null,
"group_id": 155276495180,
"aweme_id": "155276495187",
"music": {
"position": null,
"status": 1,
"id": 155276495180,
"mid": "155276495185",
"author": "王大锤丶",
"cover_medium": {
"url_list": [
"https://p9-dy.byteimg.com/aweme/720x720/fa21000c9b15527649518.jpeg?from=15527649518",
"https://p3-dy-ipv6.byteimg.com/aweme/720x720/fa21000c9b15527649518.jpeg?from=15527649518",
"https://p6-dy-ipv6.byteimg.com/aweme/720x720/fa21000c9b15527649518.jpeg?from=15527649518"
]
},
"uri": "fa21000c9b15527649518"
},
"cover_thumb": {}
}
{
"url_list": [
"https://p26-dy.byteimg.com/aweme/100x100/fa21000c9b15527649518.jpeg?from=15527649518",
"https://p3-dy-ipv6.byteimg.com/aweme/100x100/fa21000c9b15527649518.jpeg?from=15527649518",
"https://p6-dy-ipv6.byteimg.com/aweme/100x100/fa21000c9b15527649518.jpeg?from=15527649518"
],
"uri": "fa21000c9b15527649518",
"play_url": {
"uri": "http://p1-dy.byteimg.com/obj/15527649518c985cd3ca9",
"url_list": [
"http://p1-dy.byteimg.com/obj/15527649518c985cd3ca9",
"http://p9-dy.byteimg.com/obj/15527649518c985cd3ca9"
]
},
"title": "@王大锤丶创作的原声",
"cover_hd": {
"uri": "fa21000c9b15527649518",
"url_list": [
"https://p3-dy-ipv6.byteimg.com/aweme/1080x1080/fa21000c9b15527649518.jpeg?from=15527649518",
"https://p26-dy.byteimg.com/aweme/1080x1080/fa21000c9b15527649518.jpeg?from=15527649518"
]
}
}

重构后的内容:

[https://p6-dy-ipv6.byteimg.com/aweme/1080x1080/fa21000c9b15527649518.jpeg?from=15527649518](https://p6-dy-ipv6.byteimg.com/aweme/1080x1080/fa21000c9b15527649518.jpeg?from=15527649518)
Cover Large:
- URL List: [https://p3-dy-ipv6.byteimg.com/aweme/1080x1080/fa21000c9b15527649518.jpeg?from=15527649518](https://p3-dy-ipv6.byteimg.com/aweme/1080x1080/fa21000c9b15527649518.jpeg?from=15527649518),
[https://p26-dy.byteimg.com/aweme/1080x1080/fa21000c9b15527649518.jpeg?from=15527649518](https://p26-dy.byteimg.com/aweme/1080x1080/fa21000c9b15527649518.jpeg?from=15527649518),
[https://p6-dy-ipv6.byteimg.com/aweme/1080x1080/fa21000c9b15527649518.jpeg?from=15527649518](https://p6-dy-ipv6.byteimg.com/aweme/1080x1080/fa21000c9b15527649518.jpeg?from=15527649518)
]
Duration: 15
Image Informations: null
Risk Informations:
- warn: false
- type: 0
- content: null
Geofencing: null
Label Top Text: null
Long Video: null
Statistics:
- digg_count: 0
- play_count: 0
- aweme_id: 155276495187
- comment_count: 0
Aweme Type: 4
Comment List: null
Is Preview: 0

首先,我们需要从给定的JSON数据中提取出最终的URL。根据描述,这个URL是关于一个名为”@王大锤丶发了一个抖音短视频,你尽管点开,不好看算我输!”的视频的链接。 接下来,我们可以使用JavaScript代码来解析这个JSON数据,并提取出URL:

const data = [
{
"share_url": "https://www.iesdouyin.com/share/video/155276495187/?region=&mid=155276495185&u_code=48&titleType=",
"share_info": {
"share_desc": "在抖音,记录美好生活",
"share_title": "@王大锤丶发了一个抖音短视频,你尽管点开,不好看算我输!",
"share_weibo_desc": "#在抖音,记录美好生活#@王大锤丶发了一个抖音短视频,你尽管点开,不好看算我输!"
},
"author_user_id": 15527649518,
"promotions": null
},
// 其他数据...
];
// 提取URL
const url = data[0].share_url;
console.log(url);

这段代码将输出以下结果:

https://www.iesdouyin.com/share/video/155276495187/?region=&mid=155276495185&u_code=48&titleType=

这就是我们需要的可以下载视频的URL。

  1. 实际上,我们并没有获取到真正的视频链接。这个链接有水印,而真正的链接只需要将 “https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f500000bc1oaeqkr6g02kqoredg&ratio=720p&line=0” 这个部分替换为 “https://aweme.snssdk.com/aweme/v1/play/?video_id=v0200f500000bc1oaeqkr6g02kqoredg&ratio=720p&line=0”。 现在我们已经得到了可以打开观看的视频链接,但是使用代码下载这个链接仍然无法成功。
  2. 到目前为止,我们还没有真正得到可以下载的视频地址。实际上,真正的视频地址隐藏在页面的header中,有一个location属性对应的链接就是真实的视频地址。截图显示了在IDEA访问该链接时debug状态下显示的location属性。 这个链接无法打开,但是我们下载视频时还是根据这个链接来下载的。具体来说,我们需要根据这个链接进行下载操作。 在重构内容时,我们需要注意代码的可读性和结构。以下是根据提供的内容重构后的Java代码:
package com.aaa.test;
import cn.hutool.core.map.MapUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
/**
* 示例代码用于查看纯文本内容和复制代码
*/
public class Test {
public static void main(String[] args) throws Exception {
// 获取视频链接和视频路径
String url = "https://v.douyin.com/JSefMcD/";
String videoPath = "https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=";
// 连接网页并设置User-Agent
Connection con = Jsoup.connect(url);
con.header("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1");
// 读取网页内容
String content = new String(con.getContent());
// 解析内容为JSON对象
JSONObject jsonObject = JSONObject.parseObject(content);
// 获取视频标题、日期等信息
String title = jsonObject.getString("title");
String date = jsonObject.getString("date");
// 输出结果
System.out.println("视频标题: " + title);
System.out.println("视频日期: " + date);
}
}

这段代码首先导入了必要的类,然后定义了一个名为Test的类和一个main方法。在main方法中,我们通过Jsoup.connect方法连接到给定的URL,并使用header方法设置User-Agent头部信息。接下来,我们读取网页内容并将其转换为字符串。之后,我们将字符串解析为一个JSON对象。最后,我们从JSON对象中提取视频的标题和日期,并将它们输出到控制台。

Connection con = JDBCUtil.getConnection();
Connection.Response resp = con.method(Connection.Method.GET).execute();
String strUrl = resp.url().toString();
String itemId = strUrl.substring(strUrl.indexOf("video/"), strUrl.lastIndexOf("/")).replace("video/", "");
String videoUrl = videoPath + itemId;
String jsonStr = Jsoup.connect(videoUrl).ignoreContentType(true).execute().body();
JSONObject json = new JSONObject(jsonStr);
String videoAddress = json.getJSONArray("item_list").getJSONObject(0).getJSONObject("video").getJSONObject("play_addr").getJSONArray("url_list").get(0).toString();
HashMap headers = MapUtil.newHashMap();
headers.put("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1");
String replace = videoAddress.replace("playwm", "play");
System.out.println(replace);
HttpResponse execute = HttpUtil.createGet(replace).addHeaders(headers).execute();
String finalVideoAddress = execute.header("Location");
downloadVideo(finalVideoAddress);
private static void downloadVideo(String videoAddress) {
int byteRead;
try {
URL url = new URL(videoAddress);
//获取链接
URLConnection conn = url.openConnection();
//输入流
InputStream inStream = conn.getInputStream();
//封装一个保存文件的路径对象
File fileSavePath = new File(fileSavePath);
//注:如果保存文件夹不存在,那么则创建该文件夹
if (!fileParent.exists()) {
fileParent.mkdirs();
}
//写入文件
FileOutputStream fs = new FileOutputStream(fileSavePath);
byte[] buffer = new byte[1024];
while ((byteRead = inStream.read(buffer)) != -1) {
fs.write(buffer, 0, byteRead);
}
inStream.close();
fs.close();
System.out.println("-----视频保存路径-----\n" + fileSavePath.getAbsolutePath());
} catch (FileNotFoundException e) {
//处理文件未找到异常
} catch (IOException e) {
//处理I/O异常
}
}