|
@@ -0,0 +1,230 @@
|
|
|
|
|
+package com.nexo.model.douyin;
|
|
|
|
|
+
|
|
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
|
|
+import com.nexo.common.core.utils.OkHttpClientUtils;
|
|
|
|
|
+import com.nexo.common.core.utils.StringUtils;
|
|
|
|
|
+import com.nexo.model.douyin.utils.DouYinUtils;
|
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
+import org.junit.jupiter.api.Test;
|
|
|
|
|
+import org.springframework.boot.test.context.SpringBootTest;
|
|
|
|
|
+
|
|
|
|
|
+import javax.script.Invocable;
|
|
|
|
|
+import javax.script.ScriptEngine;
|
|
|
|
|
+import javax.script.ScriptEngineManager;
|
|
|
|
|
+import javax.script.ScriptException;
|
|
|
|
|
+import java.io.FileReader;
|
|
|
|
|
+import java.io.UnsupportedEncodingException;
|
|
|
|
|
+import java.net.URLDecoder;
|
|
|
|
|
+import java.net.URLEncoder;
|
|
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
|
|
+import java.util.*;
|
|
|
|
|
+import java.util.regex.Matcher;
|
|
|
|
|
+import java.util.regex.Pattern;
|
|
|
|
|
+
|
|
|
|
|
+import static org.apache.ibatis.ognl.DynamicSubscript.mid;
|
|
|
|
|
+
|
|
|
|
|
+@Slf4j
|
|
|
|
|
+@SpringBootTest
|
|
|
|
|
+public class 抖音测试工具类 {
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ public void 单个作品解析() {
|
|
|
|
|
+ String 抖音视频链接 = "1.23 cAG:/ :0pm 12/29 A@G.IV p身材教程来啦~ # 剪辑教程 https://v.douyin.com/wssqLCJ9O4c/ 复制此链接,打开Dou音搜索,直接观看视频!";
|
|
|
|
|
+ String 抖音链接 = "5.66 :6pm 01/27 h@o.Qk mDh:/ 手机全屏壁纸。# 性感 # 完美身材 https://v.douyin.com/qDWqlDX8ouQ/ 复制此链接,打开Dou音搜索,直接观看视频!";
|
|
|
|
|
+ String string = DouYinUtils.getRegexString(抖音链接, "[a-zA-z]+://[^\\s]*", 0);
|
|
|
|
|
+ HashMap<String, String> hashMap = new HashMap<>();
|
|
|
|
|
+ hashMap.put("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1 Edg/148.0.0.0");
|
|
|
|
|
+ String done = OkHttpClientUtils.doGetFollowRedirects(string, hashMap);
|
|
|
|
|
+ String string1 = StringUtils.extractMiddleText(done, "\"", "\"");
|
|
|
|
|
+ String string2 = OkHttpClientUtils.doGetFollowRedirects(string1, hashMap);
|
|
|
|
|
+ String right = StringUtils.right(string2, "window._ROUTER_DATA = ");
|
|
|
|
|
+ String left = StringUtils.left(right, "</script>");
|
|
|
|
|
+ JSONObject jsonObject = JSONObject.parseObject(DouYinUtils.decodeUnicode(left));
|
|
|
|
|
+ JSONObject data = jsonObject.getJSONObject("loaderData").getJSONObject("video_(id)/page");
|
|
|
|
|
+ data = data.getJSONObject("videoInfoRes").getJSONArray("item_list").getJSONObject(0);
|
|
|
|
|
+ log.info("{}", data);
|
|
|
|
|
+ log.info("===================== 发布者 ========================");
|
|
|
|
|
+ String sec_uid = data.getJSONObject("author").getString("sec_uid");
|
|
|
|
|
+ log.info("sec_uid:{}", sec_uid);
|
|
|
|
|
+ String short_id = data.getJSONObject("author").getString("short_id");
|
|
|
|
|
+ log.info("short_id:{}", short_id);
|
|
|
|
|
+ String nickname = data.getJSONObject("author").getString("nickname");
|
|
|
|
|
+ log.info("nickname:{}", nickname);
|
|
|
|
|
+ String signature = data.getJSONObject("author").getString("signature");
|
|
|
|
|
+ log.info("signature:{}", signature);
|
|
|
|
|
+
|
|
|
|
|
+ log.info("===================== 信息 ========================");
|
|
|
|
|
+ if (data.getInteger("aweme_type") == 4) {
|
|
|
|
|
+ String play_addr = data.getJSONObject("video").getJSONObject("play_addr").getJSONArray("url_list").getString(0);
|
|
|
|
|
+ log.info("play_addr:{}", play_addr.replaceAll("playwm", "play"));
|
|
|
|
|
+ String cover = data.getJSONObject("video").getJSONObject("cover").getJSONArray("url_list").getString(0);
|
|
|
|
|
+ log.info("cover:{}", cover);
|
|
|
|
|
+ } else if (data.getInteger("aweme_type") == 2) {
|
|
|
|
|
+ for (int i = 0; i < data.getJSONArray("images").size(); i++) {
|
|
|
|
|
+ String imgs = data.getJSONArray("images").getJSONObject(i).getJSONArray("url_list").getString(0);
|
|
|
|
|
+ log.info("img[{}]:{}", i + 1, imgs);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ String desc = data.getString("desc");
|
|
|
|
|
+ log.info("desc:{}", desc);
|
|
|
|
|
+ Integer comment_count = data.getJSONObject("statistics").getInteger("comment_count");
|
|
|
|
|
+ Integer share_count = data.getJSONObject("statistics").getInteger("share_count");
|
|
|
|
|
+ Integer digg_count = data.getJSONObject("statistics").getInteger("digg_count");
|
|
|
|
|
+ Integer collect_count = data.getJSONObject("statistics").getInteger("collect_count");
|
|
|
|
|
+ log.info("comment_count:{}", comment_count);
|
|
|
|
|
+ log.info("share_count:{}", share_count);
|
|
|
|
|
+ log.info("digg_count:{}", digg_count);
|
|
|
|
|
+ log.info("collect_count:{}", collect_count);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ public void 获取用户作品列表() {
|
|
|
|
|
+ String 分享连接 = "0- 长按复制此条消息,打开抖音搜索,查看TA的更多作品。 https://v.douyin.com/iz6uY8RfrJ8/ 7@5.com :2pm";
|
|
|
|
|
+ String string = DouYinUtils.getRegexString(分享连接, "[a-zA-z]+://[^\\s]*", 0);
|
|
|
|
|
+ String done = OkHttpClientUtils.doGetFollowRedirects(string, null);
|
|
|
|
|
+ String mid = null;
|
|
|
|
|
+ try {
|
|
|
|
|
+ mid = URLDecoder.decode(StringUtils.extractMiddleText(done, "\"", "\""), "UTF-8");
|
|
|
|
|
+ } catch (UnsupportedEncodingException e) {
|
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
|
|
+ }
|
|
|
|
|
+ String maxcursor = "";
|
|
|
|
|
+ String sec_user_id = DouYinUtils.getRegexString(mid, "user/(.*?)\\?", 1);
|
|
|
|
|
+ log.info("sec_user_id:{}", sec_user_id);
|
|
|
|
|
+ Integer count = 0;
|
|
|
|
|
+ while (true) {
|
|
|
|
|
+ String params = "device_platform=webapp&aid=6383&channel=channel_pc_web&sec_user_id=" + sec_user_id + "&max_cursor=" + maxcursor + "&locate_item_id=7388761148507639094&locate_query=false&show_live_replay_strategy=1&need_time_list=" + "0" + "&time_list_query=0&whale_cut_token=&cut_version=1&count=18&publish_video_strategy_type=2&update_version_code=170400&pc_client_type=1&version_code=290100&version_name=29.1.0&cookie_enabled=true&screen_width=1832&screen_height=314&browser_language=zh-CN&browser_platform=Win32&browser_name=Edge&browser_version=126.0.0.0&browser_online=true&engine_name=Blink&engine_version=126.0.0.0&os_name=Android&os_version=6.0&cpu_core_num=12&device_memory=8&platform=Android&downlink=10&effective_type=4g&round_trip_time=150&webid=7347601222205687359&verifyFp=verify_lwllt9d5_131z6m2c_JOGv_4TDi_Aoje_kOMojbHCPw0e&fp=verify_lwllt9d5_131z6m2c_JOGv_4TDi_Aoje_kOMojbHCPw0e&msToken=MIOLSj1Hic1rlNKxvhty424gjUhagKo0ti6PK1s9uFfs0keS0miQ0metd3ZljkX0KjkQU_3nmJZm8tuYhMjIC1jntmfmuTRAfcZEbz1UzWZVqMDrHgg%3D";
|
|
|
|
|
+ String aBogus = DouYinUtils.getABogus(params);
|
|
|
|
|
+ String url = "https://www.douyin.com/aweme/v1/web/aweme/post/?" + params + "&a_bogus=" + aBogus + "&verifyFp=verify_lwllt9d5_131z6m2c_JOGv_4TDi_Aoje_kOMojbHCPw0e&fp=verify_lwllt9d5_131z6m2c_JOGv_4TDi_Aoje_kOMojbHCPw0e";
|
|
|
|
|
+ HashMap<String, String> header = DouYinUtils.getHeader();
|
|
|
|
|
+ String reqStr = OkHttpClientUtils.doGet(url, null, header);
|
|
|
|
|
+ // 解析json
|
|
|
|
|
+ JSONObject reqJson = JSONObject.parseObject(reqStr);
|
|
|
|
|
+ maxcursor = reqJson.getString("max_cursor");
|
|
|
|
|
+ JSONArray awemeList = reqJson.getJSONArray("aweme_list");
|
|
|
|
|
+ count += awemeList.size();
|
|
|
|
|
+ log.info("maxcursor:{}", maxcursor);
|
|
|
|
|
+ log.info("aweme_list:{}", awemeList.size());
|
|
|
|
|
+ if (reqJson.getInteger("has_more") != 1) {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info("count:{}", count);
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ public void 获取用户信息() {
|
|
|
|
|
+ String 分享连接 = "0- 长按复制此条消息,打开抖音搜索,查看TA的更多作品。 https://v.douyin.com/iz6uY8RfrJ8/ 7@5.com :2pm";
|
|
|
|
|
+ String string = DouYinUtils.getRegexString(分享连接, "[a-zA-z]+://[^\\s]*", 0);
|
|
|
|
|
+ String done = OkHttpClientUtils.doGetFollowRedirects(string, null);
|
|
|
|
|
+ String mid = null;
|
|
|
|
|
+ try {
|
|
|
|
|
+ mid = URLDecoder.decode(StringUtils.extractMiddleText(done, "\"", "\""), "UTF-8");
|
|
|
|
|
+ } catch (UnsupportedEncodingException e) {
|
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info("mid:{}", mid);
|
|
|
|
|
+ String sec_user_id = DouYinUtils.getRegexString(mid, "user/(.*?)\\?", 0);
|
|
|
|
|
+ sec_user_id = StringUtils.extractMiddleText(sec_user_id, "user/", "?");
|
|
|
|
|
+ log.info("sec_user_id:{}", sec_user_id);
|
|
|
|
|
+ String params = "?device_platform=webapp&aid=6383&channel=channel_pc_web&publish_video_strategy_type=2&source=channel_pc_web&sec_user_id=" + sec_user_id + "&personal_center_strategy=1&profile_other_record_enable=1&land_to=1&update_version_code=170400&pc_client_type=1&pc_libra_divert=Windows&support_h265=0&support_dash=1&cpu_core_num=24&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1920&screen_height=1080&browser_language=zh-CN&browser_platform=Win32&browser_name=Edge&browser_version=148.0.0.0&browser_online=true&engine_name=Blink&engine_version=148.0.0.0&os_name=Windows&os_version=10&device_memory=32&platform=PC&downlink=10&effective_type=4g&round_trip_time=50&webid=7639313678160397875";
|
|
|
|
|
+ String aBogus = DouYinUtils.getABogus(params);
|
|
|
|
|
+ String url = "https://www.douyin.com/aweme/v1/web/user/profile/other/" + params + "&a_bogus=" + aBogus + "&verifyFp=verify_mp4xmi43_R2ZADT9W_IKha_4C4e_9b3a_ctEUtT2EsPOe&fp=verify_mp4xmi43_R2ZADT9W_IKha_4C4e_9b3a_ctEUtT2EsPOe";
|
|
|
|
|
+ log.info("url:{}", url);
|
|
|
|
|
+ HashMap<String, String> header = DouYinUtils.getHeader();
|
|
|
|
|
+ String reqStr = OkHttpClientUtils.doGet(url, null, header);
|
|
|
|
|
+ // 解析json
|
|
|
|
|
+ JSONObject reqJson = JSONObject.parseObject(reqStr);
|
|
|
|
|
+ log.info("reqJson:{}", reqJson);
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ public void 获取抖音热榜() {
|
|
|
|
|
+ String url = "https://so-landing.douyin.com/aweme/v1/hot/search/list/?aid=581610&detail_list=1&board_type=0&board_sub_type=&need_board_tab=true&need_covid_tab=false&version_code=32.3.0 ";
|
|
|
|
|
+ String string = OkHttpClientUtils.doGet(url);
|
|
|
|
|
+ JSONObject jsonObject = JSONObject.parseObject(string);
|
|
|
|
|
+ JSONArray jsonArray = jsonObject.getJSONObject("data").getJSONArray("word_list");
|
|
|
|
|
+ for (int i = 0; i < jsonArray.size(); i++) {
|
|
|
|
|
+ JSONObject wordJson = jsonArray.getJSONObject(i);
|
|
|
|
|
+ if (wordJson.containsKey("group_id")) {
|
|
|
|
|
+ String url2 = null;
|
|
|
|
|
+ try {
|
|
|
|
|
+ url2 = "https://so.douyin.com/s?is_from_mobile_home=1&search_entrance=aweme&enter_method=hot_list_page&innerWidth=430&innerHeight=932&reloadNavStart=1778841683198&is_no_width_reload=0&keyword=" + URLEncoder.encode(wordJson.getString("word"), "UTF-8") + "&gid=" + wordJson.getString("group_id");
|
|
|
|
|
+ } catch (UnsupportedEncodingException e) {
|
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
|
|
+ }
|
|
|
|
|
+ HashMap<String, String> hashMap = new HashMap<>();
|
|
|
|
|
+ hashMap.put("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1 Edg/148.0.0.0");
|
|
|
|
|
+
|
|
|
|
|
+ String string2 = OkHttpClientUtils.doGet(url2, null, hashMap);
|
|
|
|
|
+ String substring = string2.substring(string2.indexOf("let data = {\"business_data\":") + "let data = {\"business_data\":".length(), string2.indexOf(",\"render_info\""));
|
|
|
|
|
+ JSONArray parsed = JSONObject.parseArray(substring);
|
|
|
|
|
+ JSONObject object = new JSONObject();
|
|
|
|
|
+ object.put("group_id", wordJson.getString("group_id"));
|
|
|
|
|
+ object.put("word", wordJson.getString("word"));
|
|
|
|
|
+ JSONArray array = new JSONArray();
|
|
|
|
|
+ for (int i1 = 0; i1 < parsed.size(); i1++) {
|
|
|
|
|
+ String string1 = parsed.getJSONObject(i1).getJSONObject("data").getString("provider_doc_id_str");
|
|
|
|
|
+ if (parsed.getJSONObject(i1).getInteger("type") == 1) {
|
|
|
|
|
+ array.add("https://www.douyin.com/video/" + string1);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ object.put("list", array);
|
|
|
|
|
+ log.info("{}", object);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ public void 获取直播流() {
|
|
|
|
|
+ String url = "https://live.douyin.com/660321581729";
|
|
|
|
|
+ HashMap<String, String> hashMap = new HashMap<>();
|
|
|
|
|
+ hashMap.put("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1 Edg/148.0.0.0");
|
|
|
|
|
+ String done = OkHttpClientUtils.doGet(url, null, hashMap);
|
|
|
|
|
+ String roomId = DouYinUtils.getRegexString(done, "roomId=\"(.*?)\"", 1);
|
|
|
|
|
+ if (StringUtils.isEmpty(roomId)) {
|
|
|
|
|
+ throw new RuntimeException("未找到房间号");
|
|
|
|
|
+ }
|
|
|
|
|
+ String url2 = "https://webcast.amemv.com/webcast/room/reflow/info/?type_id=0&live_id=1&room_id=" + roomId + "&sec_user_id=&app_id=1128";
|
|
|
|
|
+ String string = OkHttpClientUtils.doGet(url2, null, hashMap);
|
|
|
|
|
+ JSONObject data = JSONObject.parseObject(string);
|
|
|
|
|
+ JSONObject stream = data.getJSONObject("data").getJSONObject("room").getJSONObject("stream_url");
|
|
|
|
|
+ JSONObject resolutionName = stream.getJSONObject("resolution_name");
|
|
|
|
|
+ log.info("========================== flv ==========================");
|
|
|
|
|
+ JSONObject flv_pull_url = stream.getJSONObject("flv_pull_url");
|
|
|
|
|
+ flv_pull_url.forEach((key, value) -> {
|
|
|
|
|
+ String resolution = resolutionName.getString(key);
|
|
|
|
|
+ log.info("{}:{}", resolution, value);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ log.info("========================== hls ==========================");
|
|
|
|
|
+ JSONObject hls_pull_url_map = stream.getJSONObject("hls_pull_url_map");
|
|
|
|
|
+ hls_pull_url_map.forEach((key, value) -> {
|
|
|
|
|
+ String resolution = resolutionName.getString(key);
|
|
|
|
|
+ log.info("{}:{}", resolution, value);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ log.info("========================== 主播信息 ==========================");
|
|
|
|
|
+
|
|
|
|
|
+ JSONObject owner = data.getJSONObject("data").getJSONObject("room").getJSONObject("owner");
|
|
|
|
|
+ String avatar = owner.getJSONObject("avatar_large").getJSONArray("url_list").getString(0);
|
|
|
|
|
+ log.info("头像:{}", avatar);
|
|
|
|
|
+ log.info("昵称:{}", owner.getString("nickname"));
|
|
|
|
|
+ log.info("签名:{}", owner.getString("signature"));
|
|
|
|
|
+ Integer following_count = owner.getJSONObject("follow_info").getInteger("following_count");
|
|
|
|
|
+ log.info("关注数:{}", following_count);
|
|
|
|
|
+ Integer follower_count = owner.getJSONObject("follow_info").getInteger("follower_count");
|
|
|
|
|
+ log.info("粉丝数:{}", follower_count);
|
|
|
|
|
+ log.info("SECUID:{}", owner.getString("sec_uid"));
|
|
|
|
|
+ log.info("抖音号:{}", owner.getString("display_id"));
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|