在做短视频的时候,朋友经常问我这样的问题:

1. 有没有免费短视频去水印解析网站?
2. 短视频下载怎么不要水印?
3. 短视频怎么去水印?

我去网上找了一遍,要么限制次数,要么看完广告才能下载
最后还是自己做了一个,代码贴出来给你们改善

需要导jsoup包
https://file.bybbs.org/attachment/2021/7_6/9f37c8df12bf4065a0e8000097010c23.png?x-oss-process=style/internet
这富文本编辑框有点拉跨,xml格式竟然给我转换

实现代码
import cn.hutool.core.map.MapUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**

org.jsoup
jsoup
1.12.2

*/
public class VideoService {

/**
* 方法描述: 快手解析下载视频
* 用Jsoup 爬快手视频
* 1、首先获取js信息
* 2、取出window.pageData的信息
* @param url
* @author lxb
*/
public static String kuaiShouParseUrl(String url) {
HashMap headers = new HashMap<>();
headers.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
headers.put("Accept-Charset", "GB2312,utf-8;q=0.7,*;q=0.7");
headers.put("Accept-Encoding", "gzip, deflate, sdch, br");
headers.put("Accept-Language", "zh-cn,zh;q=0.8");
headers.put("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16D57 Version/12.0 Safari/604.1");
String redirectUrl = HttpUtil.createGet(url).addHeaders(headers).execute().header("Location");
System.out.println(redirectUrl);
String body = HttpUtil.createGet(redirectUrl).addHeaders(headers).execute().body();
Document doc = Jsoup.parse(body);
Elements videoElement = doc.select("script[type=text/javascript]");
String videoInfo = videoElement.get(3).data().replaceAll("window.pageData= ", "");

// 获取当前视频用户信息
JSONObject json = JSONObject.parseObject(videoInfo);
// 获取当前视频信息
JSONObject video = json.getJSONObject("video");
// 无水印视频地址
String videoUrl = video.getString("srcNoMark");

// 截取前面的数据
videoUrl = videoUrl.substring(0, videoUrl.indexOf("?"));
return videoUrl;
}

/**
* 抖音解析下载视频
* 用Jsoup 解析
* 1、先获取该抖音视频ID
* 2、调用抖音接口获取视频真实地址 https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids= + 抖音视频ID
* 3、获取抖音无水印地址 把 https://aweme.snssdk.com/aweme/v1/playwm/ 的playwm替换成play
* 4、重新请求一次抖音无水印地址获取该视频原地址
* @param url
* @author lxb
*/
public static String douYinParseUrl(String url) {
String videoUrl = "";
try {
Connection con= Jsoup.connect(url);
con.header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
con.header("Accept-Charset", "GB2312,utf-8;q=0.7,*;q=0.7");
con.header("Accept-Encoding", "gzip, deflate, sdch, br");
con.header("Accept-Language", "zh-cn,zh;q=0.8");
con.header("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16D57 Version/12.0 Safari/604.1");
Connection.Response resp= con.method(Connection.Method.GET).execute();

String respUrl = resp.url().toString();

/**
* 加上/video/这个7位数
* 获取 视频ID = 获取/video/ 和 / 中间的数据
*/
String itemId = respUrl.split("/video/")[1].split("/")[0];

/**
* (固定)https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=
* videoUrl = 视频链接 + 视频ID
*/
String trueAddress= "https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=" + itemId;
String jsonStr = Jsoup.connect(trueAddress).ignoreContentType(true).execute().body();

JSONObject obj = JSONObject.parseObject(jsonStr);

// 获取当前的视频的真实url
String videoAddress= obj.getJSONArray("item_list").getJSONObject(0).getJSONObject("video").getJSONObject("play_addr").getJSONArray("url_list").get(0).toString();
/**
* https://aweme.snssdk.com/aweme/v1/playwm/?video_id=
* 把playwm替换成play
*/
videoAddress = videoAddress.replaceAll("playwm", "play");

// 重新请求一次抖音无水印地址
Map headers = MapUtil.newHashMap();
headers.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
headers.put("Accept-Charset", "GB2312,utf-8;q=0.7,*;q=0.7");
headers.put("Accept-Encoding", "gzip, deflate, sdch, br");
headers.put("Accept-Language", "zh-cn,zh;q=0.8");
headers.put("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16D57 Version/12.0 Safari/604.1");

// 该视频的原地址
videoUrl = HttpUtil.createGet(videoAddress).addHeaders(headers).execute().header("Location");

}catch (Exception e){
e.printStackTrace();
}
return videoUrl;
}

/**
* 抖音火山解析下载视频
* @param url
* @author lxb
*/
public static String huoShanParseUrl(String url) {
String videoUrl = "";
try {
Connection con= Jsoup.connect(url);
con.header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
con.header("Accept-Charset", "GB2312,utf-8;q=0.7,*;q=0.7");
con.header("Accept-Encoding", "gzip, deflate, sdch, br");
con.header("Accept-Language", "zh-cn,zh;q=0.8");
con.header("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16D57 Version/12.0 Safari/604.1");
Connection.Response resp= con.method(Connection.Method.GET).execute();

String respUrl = resp.url().toString();

String itemId = respUrl.split("item_id=")[1].split("&")[0];

/**
* (固定)https://share.huoshan.com/api/item/info?item_id=
* videoUrl = 视频链接 + 视频ID
*/
String trueAddress= "https://share.huoshan.com/api/item/info?item_id=" + itemId;
String jsonStr = Jsoup.connect(trueAddress).ignoreContentType(true).execute().body();

JSONObject obj = JSONObject.parseObject(jsonStr);

// 获取当前的视频的真实url
String video_url= obj.getJSONObject("data").getJSONObject("item_info").getString("url");
String video_id = video_url.split("video_id=")[1].split("&")[0];

String real_url = "http://hotsoon.snssdk.com/hotsoon/item/video/_playback/?video_id=" + video_id;

// 重新请求一次无水印地址
Map headers = MapUtil.newHashMap();
headers.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
headers.put("Accept-Charset", "GB2312,utf-8;q=0.7,*;q=0.7");
headers.put("Accept-Encoding", "gzip, deflate, sdch, br");
headers.put("Accept-Language", "zh-cn,zh;q=0.8");
headers.put("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16D57 Version/12.0 Safari/604.1");

// 该视频的原地址
videoUrl = HttpUtil.createGet(real_url).addHeaders(headers).execute().header("Location");

}catch (Exception e){
e.printStackTrace();
}
return videoUrl;
}

/**
* 微视解析下载视频
* @param url
* @author lxb
*/
public static String weiShiParseUrl(String url) {
String videoUrl = "";
try {
Connection con= Jsoup.connect(url);
con.header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
con.header("Accept-Charset", "GB2312,utf-8;q=0.7,*;q=0.7");
con.header("Accept-Encoding", "gzip, deflate, sdch, br");
con.header("Accept-Language", "zh-cn,zh;q=0.8");
con.header("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16D57 Version/12.0 Safari/604.1");
Connection.Response resp= con.method(Connection.Method.GET).execute();

String respUrl = resp.url().toString();

String itemId = respUrl.split("feedid=")[1].split("&")[0];

/**
* (固定)https://h5.qzone.qq.com/webapp/json/weishi/WSH5GetPlayPage?feedid
* videoUrl = 视频链接 + 视频ID
*/
String trueAddress= "https://h5.qzone.qq.com/webapp/json/weishi/WSH5GetPlayPage?feedid=" + itemId;
String jsonStr = Jsoup.connect(trueAddress).ignoreContentType(true).execute().body();

JSONObject obj = JSONObject.parseObject(jsonStr);

// 获取当前的视频的真实url
videoUrl= obj.getJSONObject("data").getJSONArray("feeds").getJSONObject(0).getString("video_url");

}catch (Exception e){
e.printStackTrace();
}
return videoUrl;
}


public static void main(String[] args){
// System.out.println(weiShiParseUrl(Utils.filterUrl("嗨,我正在参加微视“谁是王者人气英雄”挑战赛,快来帮我投票吧!>>https://h5.weishi.qq.com/weishi/wsplay/challenge2?feedid=78sKriqyF1KyJk2cT&challegeid=100543&spid=1558186608003629&qua=v1_iph_weishi_8.2.7_241_app_a&chid=127081004&pkg=&attach=cp_reserves3_1190370002")));
// System.out.println(huoShanParseUrl(filterUrl("金名美食(家常菜)在火山分享了视频,快来围观!传送门戳我>>https://share.huoshan.com/hotsoon/s/FJ8Wl9cV0d8/ 复制此链接,打开【抖音火山版】,直接观看视频~")));
// System.out.println(kuaishouParseUrl(filterUrl("出去玩就这?就这? #黑丝 https://v.kuaishou.com/6lIPLQ 复制此消息,打开【快手】直接观看!")));
// System.out.println(douYinParseUrl(filterUrl("二三十岁人了,都是老样子,人很普通,说话又不够甜,长得也一般般,重要是,还没什么钱。#情感文字视频 https://v.douyin.com/JPoaJry/ 复制此链接,打开抖音,直接看观视频!")));
// System.out.println(filterUrl("二三十岁人了,都是老样子,人很普通,说话又不够甜,长得也一般般,重要是,还没什么钱。#情感文字视频 https://v.douyin.com/JPoaJry/ 复制此链接,打开抖音,直接看观视频!"));
}

// 保存视频
public static void save(String s) throws Exception {
long start = System.currentTimeMillis();


// 打开和URL之间的连接

HttpURLConnection conn2 = (HttpURLConnection) new URL(s).openConnection();


// 设置通用的请求属性

conn2.setRequestProperty("accept", "*/*");
conn2.setRequestProperty("connection", "Keep-Alive");
conn2.setRequestProperty("Accept-Charset", "utf-8");
conn2.setRequestProperty("Content-Type", "audio/mp3");
conn2.setRequestProperty("user-agent", "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn2.setRequestMethod("GET");
conn2.connect();

// 定义BufferedReader输入流来读取URL的响应

InputStream in2 = conn2.getInputStream();
String last = ".mp4";
if (s.contains("mp4")) {
last = ".mp4";
} else if (s.contains("mp3")) {
last = ".mp3";
} else {
last = ".mp4";
}



//文件保存的位置

FileOutputStream fileOutputStream = new FileOutputStream(new File("D:\\" + new Date().getTime() + last));

byte[] b = new byte[1024 * 5];
int len;
while ((len = in2.read(b)) != -1) {
fileOutputStream.write(b, 0, len);
}
long end = System.currentTimeMillis();
System.out.println("用时间:" + (end - start) + "毫秒");
fileOutputStream.flush();
fileOutputStream.close();


}
}

就这样了,我累了,斗不过这个富文本编辑框,将就看看吧