java basics ????? ???? ?? ?? ??? ?????.
?? ?? ?? ??: java ??
?? ???? ??? ??? ???.
?? Douyin ??? ???? ?? ??? ??? ?? ??? ????????. ??? ? ?????. ?? ??? ????? ??? ?? ????~
?? ? ? ??? Douyin?? "??? ???? ??? ???? ? ?? ??"? ?? ????
???? ?? ?????? ??????. ?? ??
? ?? ??? ???? ?? ?? ??? ??? ??????. 教育意義
的視頻,“男人疼媳婦就該承包全部家務(wù)活”,然后它就想把視頻下載下來,分享到她的姐妹群交流 馭夫
心得。
可是大家都知道抖音下載的視頻是帶水印,作為一個(gè)重度強(qiáng)迫癥選手這是不被允許的,沒辦法那就找找有沒有去水印工具吧,找了一圈要不就是收費(fèi),要么下載不下來,主上臉上的笑容也在逐漸消失。
我在邊上調(diào)侃了一句:也沒多難,要不我給你做一個(gè)!“你行嗎?” 然后投來了一個(gè)不屑的眼神。
哎呀!本來就開個(gè)玩笑,居然說我不行,這就不能忍了,我得證明給你看看!男人嘛,就受不了這話
先看下我做的去水印工具線上預(yù)覽效果: 47.93.6.5:8888/index
下邊和大家一起分析下做這個(gè)去水印工具的思路,很多人乍一聽 去水印
,下意識(shí)的覺得是一種什么牛比的算法,其實(shí)這是一種假象~
刨根問底
雖說要爭口氣,可剛開始做的時(shí)候我也真是一臉懵逼,因?yàn)楦静恢涝搹哪娜胧?,去水印什么原理啊?難不成我還要寫個(gè)算法?
找了一個(gè)抖音視頻的分享鏈接,一點(diǎn)點(diǎn)分析,不難發(fā)現(xiàn)這是個(gè)經(jīng)過處理的短鏈接,那這個(gè)短鏈接一定會(huì)重定向到真實(shí)的視頻地址 URL
。
https://v.douyin.com/JSkuhE4/
瀏覽器中輸入短鏈接得到了下邊這個(gè) URL
,以我的經(jīng)驗(yàn)判斷URL
中的 6820792802394262795
很有可能是視頻的唯一ID,而唯一ID通常用來作為獲取詳情接口的入?yún)ⅲズ賬 好像有點(diǎn)頭緒了。
https://www.iesdouyin.com/share/video/6820792802394262795/
趕緊祭出 F12
大法打開控制臺(tái),在眾多請(qǐng)求中發(fā)現(xiàn)這么一個(gè)接口,它居然用到了上邊的唯一ID。
https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=6820792802394262795
更驚喜的是接口返回的數(shù)據(jù)那叫一個(gè)詳細(xì),作者信息、音頻地址、視頻地址、平面圖都有。但唯獨(dú)沒有無水印的視頻 URL
。
只找到一個(gè)有水印的視頻 URL
,有點(diǎn)小失落,我又看了看這個(gè)地址,發(fā)現(xiàn) wm
和我項(xiàng)目名有點(diǎn)像啊,不就是watermark
水印的縮寫嗎?
https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f030000bqk54kg2saj3lso3oh20&ratio=720p&line=0
好像又看到了一絲希望,我趕緊修改URL
在瀏覽器中又試了一下,果然真的沒水印了。
https://aweme.snssdk.com/aweme/v1/play/?video_id=v0200f030000bqk54kg2saj3lso3oh20&ratio=720p&line=0
到這才發(fā)現(xiàn)抖音去水印
簡單的讓人感動(dòng),哈哈哈~
身體力行
既然原理都清晰了,剩下的就是一步一步實(shí)現(xiàn)功能了,原理看著挺簡單的,但實(shí)現(xiàn)中還是遇到一點(diǎn)點(diǎn)小坑,浪費(fèi)了不少時(shí)間。
實(shí)現(xiàn)過程只有簡單的三步:
- 1、從輸入框中過濾取出視頻短連接
- 2、短連接傳到后端解析出無水印的視頻
URL
- 3、視頻
URL
傳遞給前端預(yù)覽、下載
后端并沒有什么難度,一步一步按照上邊分析的流程解析真實(shí)視頻 URL

?? ?? ?? ?? ???? ?? ??? ??? ???? ??? ???: 47.93.6.5:8888/index????

???? ??
? ??? ? ?????? ?? ?? ????? ? ?????. ??? ???????~????????? ??? ????. information??????? ?? ???? ?? ??? ? ???? ??? ??? ???? ??? ?? ???????. ??? ????? ???? ?? ?? ?????? ????Douyin ???? ?? ?? ??? ?????. ??? ?? ?? ??? ??? ?? ???? ?? ??? ?? ?? ? ?????. ??? ? ?? ??? ??? ?? ??? ?? URL
? ???????. >. ??/** *?@param?url *?@author?xiaofu *?@description?獲取當(dāng)前鏈接重定向后的url *?@date?2020/9/15?12:43 */public?static?String?getLocation(String?url)?{ ????????try?{ ????????????URL?serverUrl?=?new?URL(url); ????????????HttpURLConnection?conn?=?(HttpURLConnection)?serverUrl.openConnection(); ????????????conn.setRequestMethod("GET"); ????????????conn.setInstanceFollowRedirects(false); ????????????conn.setRequestProperty("User-agent",?"ua");//模擬手機(jī)連接 ????????????conn.connect(); ????????????String?location?=?conn.getHeaderField("Location"); ????????????return?location; ????????}?catch?(Exception?e)?{ ????????????e.printStackTrace(); ????????} ????????return?""; ????}?? ????? ?? ??? ???? ??
URL
? ?????. ? ??? ??? URL
? 6820792802394262795
? ?? ?? ??? ?????. ???? ???? ????. ?? ID? ????? ????? ?? ?? ?????? ?? ????? ?????. ??~ ? ?? ??? ?? ? ????. ??/** ?*?@author?xiaofu-公眾號(hào):程序員內(nèi)點(diǎn)事 ?*?@description?抖音無水印視頻下載 ?*?@date?2020/9/15?18:44 ?*/@Slf4j @Controllerpublic?class?DYController?{ ????public?static?String?DOU_YIN_BASE_URL?=?"https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids="; ????/** ?????*?@param?url ?????*?@author?xiaofu ?????*?@description?解析抖音無水印視頻 ?????*?@date?2020/9/15?12:43 ?????*/ ????@RequestMapping("/parseVideoUrl") ????@ResponseBody????public?String?parseVideoUrl(@RequestBody?String?url)?throws?Exception?{ ????????DYDto?dyDto?=?new?DYDto(); ????????try?{ ????????????url?=?URLDecoder.decode(url).replace("url=",?""); ????????????/** ?????????????*?1、短連接重定向后的?URL ?????????????*/ ????????????String?redirectUrl?=?CommonUtils.getLocation(url); ????????????/** ?????????????*?2、拿到視頻對(duì)應(yīng)的?ItemId ?????????????*/ ????????????String?videoUrl?=?""; ????????????String?musicUrl?=?""; ????????????String?videoPic?=?""; ????????????String?desc?=?""; ????????????if?(!StringUtils.isEmpty(redirectUrl))?{ ????????????????/** ?????????????????*?3、用?ItemId?拿視頻的詳細(xì)信息,包括無水印視頻url ?????????????????*/ ????????????????String?itemId?=?CommonUtils.matchNo(redirectUrl); ????????????????StringBuilder?sb?=?new?StringBuilder(); ????????????????sb.append(DOU_YIN_BASE_URL).append(itemId); ????????????????String?videoResult?=?CommonUtils.httpGet(sb.toString()); ????????????????DYResult?dyResult?=?JSON.parseObject(videoResult,?DYResult.class); ????????????????/** ?????????????????*?4、無水印視頻?url ?????????????????*/ ????????????????videoUrl?=?dyResult.getItem_list().get(0) ????????????????????????.getVideo().getPlay_addr().getUrl_list().get(0) ????????????????????????.replace("playwm",?"play"); ????????????????String?videoRedirectUrl?=?CommonUtils.getLocation(videoUrl); ????????????????dyDto.setVideoUrl(videoRedirectUrl); ????????????????/** ?????????????????*?5、音頻?url ?????????????????*/ ????????????????musicUrl?=?dyResult.getItem_list().get(0).getMusic().getPlay_url().getUri(); ????????????????dyDto.setMusicUrl(musicUrl); ????????????????/** ?????????????????*?6、封面 ?????????????????*/ ????????????????videoPic?=?dyResult.getItem_list().get(0).getVideo().getDynamic_cover().getUrl_list().get(0); ????????????????dyDto.setVideoPic(videoPic); ????????????????/** ?????????????????*?7、視頻文案 ?????????????????*/ ????????????????desc?=?dyResult.getItem_list().get(0).getDesc(); ????????????????dyDto.setDesc(desc); ????????????} ????????}?catch?(Exception?e)?{ ????????????log.error("去水印異常?{}",?e); ????????} ????????return?JSON.toJSONString(dyDto); ????}}??

$.ajax({ ????url:?'/parseVideoUrl', ????type:?'POST', ????data:?{"url":?link}, ????success:?function?(data)?{ ????????$('.qsy-submit').attr('disabled',?false); ????????try?{ ????????????var?rows?=?JSON.parse(data); ????????????layer.close(index); ????????????layer.open({ ????????????????type:?1, ????????????????title:?false, ????????????????closeBtn:?1, ????????????????shadeClose:?true, ????????????????skin:?'yourclass', ????????????????content:?`<p></p><p></p><p><a><button>下載視頻</button></a></p><p><textarea>${rows['videoUrl']}</textarea><button>復(fù)制鏈接</button></p><p><a><button>下載音頻</button></a></p><video><source>?</source></video>` ????????????????//content:?`<video><source>?</source></video>` ????????????}); ????????}?catch?(error)?{ ????????????layer.alert('錯(cuò)誤信息:'?+?error,?{ ????????????????title:?'異常', ????????????????skin:?'layui-layer-lan', ????????????????closeBtn:?0, ????????????????anim:?4?//動(dòng)畫類型 ????????????}); ????????????return?false; ????????} ????}, ????error:?function?(err)?{ ????????console.log(err); ????????layer.close(index); ????????$('.qsy-submit').attr('disabled',?false); ????}, ????done:?function?()?{ ????????layer.close(index); ????}})})??

? ??? ?? ????? ?? ???? ??? ??, ??? ??, ??? ?? ? ???? ???? ???? ???. ??? ????? ?? ???
URL
? ????. 
????? ?? ??? ??? ???
URL
? ?? ????????. ??? ?? ???? wm
? ? ???? ??? ?? ??????. ?? ????????.
.????? ??? ???<!-- 解決訪問視頻url 請(qǐng)求403異常 --> ?<meta>??

?? ? ??? ?? ? ? ??? ?? ???
URL
? ???? ?????? ?? ??? ????, ?? ????? ?? ?????. ??rrreee??
????? Douyin?
???? ??
? ?? ???? ?????? ?? ?????. ???~?????????? ??? ????????? ??? ??????, ???? ??? ???? ?? ?????. ?? ??? ? ??? ?? ? ??? ? ?? ?? ??? ???? ?? ??? ??????. ?????? ???? ? ?? ??? ??? ????: ??- 1. ?? ???? ?? ??? ??? ??????.
- 2. ?? ??? ???? ???? ?? ?????. ????? ?? ???URL
- 3. ???
URL
? ???? ? ????? ?? ?????? ?????.
URL
? ????? ?????. ??注意 :我們想得到的地址
URL
,都是當(dāng)前短連接URL
經(jīng)過重定向后的URL
。而抖音有些鏈接是不支持瀏覽器訪問的,所以要手動(dòng)修改User-agent
屬性模擬移動(dòng)端訪問才可以。
/** *?@param?url *?@author?xiaofu *?@description?獲取當(dāng)前鏈接重定向后的url *?@date?2020/9/15?12:43 */public?static?String?getLocation(String?url)?{ ????????try?{ ????????????URL?serverUrl?=?new?URL(url); ????????????HttpURLConnection?conn?=?(HttpURLConnection)?serverUrl.openConnection(); ????????????conn.setRequestMethod("GET"); ????????????conn.setInstanceFollowRedirects(false); ????????????conn.setRequestProperty("User-agent",?"ua");//模擬手機(jī)連接 ????????????conn.connect(); ????????????String?location?=?conn.getHeaderField("Location"); ????????????return?location; ????????}?catch?(Exception?e)?{ ????????????e.printStackTrace(); ????????} ????????return?""; ????}
下邊是完整的后端實(shí)現(xiàn),可以看到代碼量非常的少。
/** ?*?@author?xiaofu-公眾號(hào):程序員內(nèi)點(diǎn)事 ?*?@description?抖音無水印視頻下載 ?*?@date?2020/9/15?18:44 ?*/@Slf4j @Controllerpublic?class?DYController?{ ????public?static?String?DOU_YIN_BASE_URL?=?"https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids="; ????/** ?????*?@param?url ?????*?@author?xiaofu ?????*?@description?解析抖音無水印視頻 ?????*?@date?2020/9/15?12:43 ?????*/ ????@RequestMapping("/parseVideoUrl") ????@ResponseBody????public?String?parseVideoUrl(@RequestBody?String?url)?throws?Exception?{ ????????DYDto?dyDto?=?new?DYDto(); ????????try?{ ????????????url?=?URLDecoder.decode(url).replace("url=",?""); ????????????/** ?????????????*?1、短連接重定向后的?URL ?????????????*/ ????????????String?redirectUrl?=?CommonUtils.getLocation(url); ????????????/** ?????????????*?2、拿到視頻對(duì)應(yīng)的?ItemId ?????????????*/ ????????????String?videoUrl?=?""; ????????????String?musicUrl?=?""; ????????????String?videoPic?=?""; ????????????String?desc?=?""; ????????????if?(!StringUtils.isEmpty(redirectUrl))?{ ????????????????/** ?????????????????*?3、用?ItemId?拿視頻的詳細(xì)信息,包括無水印視頻url ?????????????????*/ ????????????????String?itemId?=?CommonUtils.matchNo(redirectUrl); ????????????????StringBuilder?sb?=?new?StringBuilder(); ????????????????sb.append(DOU_YIN_BASE_URL).append(itemId); ????????????????String?videoResult?=?CommonUtils.httpGet(sb.toString()); ????????????????DYResult?dyResult?=?JSON.parseObject(videoResult,?DYResult.class); ????????????????/** ?????????????????*?4、無水印視頻?url ?????????????????*/ ????????????????videoUrl?=?dyResult.getItem_list().get(0) ????????????????????????.getVideo().getPlay_addr().getUrl_list().get(0) ????????????????????????.replace("playwm",?"play"); ????????????????String?videoRedirectUrl?=?CommonUtils.getLocation(videoUrl); ????????????????dyDto.setVideoUrl(videoRedirectUrl); ????????????????/** ?????????????????*?5、音頻?url ?????????????????*/ ????????????????musicUrl?=?dyResult.getItem_list().get(0).getMusic().getPlay_url().getUri(); ????????????????dyDto.setMusicUrl(musicUrl); ????????????????/** ?????????????????*?6、封面 ?????????????????*/ ????????????????videoPic?=?dyResult.getItem_list().get(0).getVideo().getDynamic_cover().getUrl_list().get(0); ????????????????dyDto.setVideoPic(videoPic); ????????????????/** ?????????????????*?7、視頻文案 ?????????????????*/ ????????????????desc?=?dyResult.getItem_list().get(0).getDesc(); ????????????????dyDto.setDesc(desc); ????????????} ????????}?catch?(Exception?e)?{ ????????????log.error("去水印異常?{}",?e); ????????} ????????return?JSON.toJSONString(dyDto); ????}}
前端實(shí)現(xiàn)也比較簡單,拿到后端解析出來的視頻URL
預(yù)覽播放、下載就OK了。
為快速實(shí)現(xiàn)我用了老古董JQuery
,我這個(gè)年紀(jì)的人對(duì)它感情還是很深厚的,UI
框架用的 layer.js
。源碼后邊會(huì)分享給大家,就不全貼出來了。
$.ajax({ ????url:?'/parseVideoUrl', ????type:?'POST', ????data:?{"url":?link}, ????success:?function?(data)?{ ????????$('.qsy-submit').attr('disabled',?false); ????????try?{ ????????????var?rows?=?JSON.parse(data); ????????????layer.close(index); ????????????layer.open({ ????????????????type:?1, ????????????????title:?false, ????????????????closeBtn:?1, ????????????????shadeClose:?true, ????????????????skin:?'yourclass', ????????????????content:?`<p></p><p></p><p><a><button>下載視頻</button></a></p><p><textarea>${rows['videoUrl']}</textarea><button>復(fù)制鏈接</button></p><p><a><button>下載音頻</button></a></p><video><source>?</source></video>` ????????????????//content:?`<video><source>?</source></video>` ????????????}); ????????}?catch?(error)?{ ????????????layer.alert('錯(cuò)誤信息:'?+?error,?{ ????????????????title:?'異常', ????????????????skin:?'layui-layer-lan', ????????????????closeBtn:?0, ????????????????anim:?4?//動(dòng)畫類型 ????????????}); ????????????return?false; ????????} ????}, ????error:?function?(err)?{ ????????console.log(err); ????????layer.close(index); ????????$('.qsy-submit').attr('disabled',?false); ????}, ????done:?function?()?{ ????????layer.close(index); ????}})})
注意:我們?cè)谧约旱木W(wǎng)站中引用其它網(wǎng)站的資源
URL
,由于不在同一個(gè)域名下referrer
不同,通常會(huì)遇到三方網(wǎng)站的防盜鏈攔截,所以要想正常訪問三方資源,必須要隱藏請(qǐng)求的referrer
,頁面中設(shè)置如下參數(shù)。
?<!-- 解決訪問視頻url 請(qǐng)求403異常 --> ?<meta>
還簡單做了下移動(dòng)端適配,樣式看著還可以,但是功能使用起來有點(diǎn)差強(qiáng)人意,后邊在做優(yōu)化了。
總結(jié)
很多東西就是這樣,沒認(rèn)真研究之前總感覺深不可測,可一旦接觸到技術(shù)的本質(zhì),又開始笑自己之前好蠢,懂與不懂有時(shí)就查那么一層窗戶紙。
? ??? Java ?????? Douyin ??? ???? ?? ??? ?? ??????.? ?? ?????. ??? ??? PHP ??? ????? ?? ?? ??? ?????!

? AI ??

Undress AI Tool
??? ???? ??

Undresser.AI Undress
???? ?? ??? ??? ?? AI ?? ?

AI Clothes Remover
???? ?? ???? ??? AI ?????.

Clothoff.io
AI ? ???

Video Face Swap
??? ??? AI ?? ?? ??? ???? ?? ???? ??? ?? ????!

?? ??

??? ??

???++7.3.1
???? ?? ?? ?? ???

SublimeText3 ??? ??
??? ??, ???? ?? ????.

???? 13.0.1 ???
??? PHP ?? ?? ??

???? CS6
??? ? ?? ??

SublimeText3 Mac ??
? ??? ?? ?? ?????(SublimeText3)

JDBC ????? ???? ????? ?? ?? ?? ??? ?? ?? ??? ?? ? ?? ??? ?? ?? ?? ??? ???????. 1. ????? ????? Conn.SetAutoCommit (False)?? ??????. 2. ??? ? ????? ?? ?? SQL ??? ?????. 3. ?? ??? ??? ?? Conn.commit ()?? ???? ??? ???? ???? ?? ??? ???? Conn.Rollback ()?? ??????. ???, ? ??? ???? ????, ??? ???? ????, ?? ??? ??? ?? ??? ??? ???? ? ???????. ?? ?? ?? ???? ????? ??? ???? ?? ?? ???? ???? ??? ????? ?? ??? ??? ? ?? ???? ?? ????.

?? ?? ? ?? ???? ???? ?? Java.Time ???? ???? ??????. 2. LocalDate, LocalDateTime ? LocalTime? ?? ?? ??? ??? ?????. 3. () ???? ???? ?? ??? ??? ????. 4. ???/???? ??? ???? ??? ????? ??? ??????. 5. ZonedDateTime ? Zoneid? ???? ???? ??????. 6. DateTimeFormatter? ?? ?? ? ?? ?? ?? ???; 7. ??? ?? ?? ?? ??? ????? ?? ??????. ?? Java? ?? ??? ???? ??? ??? ???? Java.Timeapi ??? ?? ??? ???????.

Pre-FormancetArtUptimeMoryUsage, Quarkusandmicronautleadduetocompile-timeprocessingandgraalvsupport, withquarkusoftenperforminglightbetterine serverless sinarios.2.thyvelopecosyste,

GO? HTTP ?? ????? ?? ??, ??, ????? IP ? ?? ??? ?? ? ? ????. 1. http.handlerfunc? ???? ????? ????, 2. ??? ???? ?? ?? ??? ?? ??? ??????. ?? ?? ??? ???? ??? ?????? ??? ????? ???? ? ?????. ?? ???? ?? ?? ??, JSON ?? ?? ? ?? ID ??? ?????.

Java 's Garbage Collection (GC)? ???? ???? ???? ??????, ?? ? ??? ??? ? ??? ??? ??? ??? ????. 1.GC? ?? ?? (? : ?? ??, ?? ???, ?? ?? ?)?? ??? ???? ????, ?? ? ??? ??? ???? ?????. 2. ?? ???? ????? ????, ?? ?? ??? ??? ???? ?? ??? ??????. 3. ?? ?? ?? ?? : ??? ?? (Eden, S0, S1)? ?? ????? ?????. ??? ??? ?? ? MajorGC? ???? ? ??? ? ????. Metaspace? ??? ?? ???? ?????. 4. JVM? ??? GC ??? ?????. SerialGC? ??? ?? ????? ?????. ParallelGC? ???? ??????. CMS? ?? ???

??? htmlinput ??? ???? ??? ???? ????? ??? ??? ?? ??? ???? ???? ? ????. 1. ???, ???, ??, ?? ? ??? ?? ??? ??? ?? ?? ?? ??? ???? ???? ??? ? ???? ??? ? ????. 2. HTML5? ?????? ??? ? ?? ?? ??? ?? ? ??? URL, ??, ?? ? ??? ?? ??? ??? ??????. 3. ?? ?? ? ? ??? ??? ???? ?? ??? ???? ???? ?? ???? ?? ???? ???? ?? ? ? ??? ?? ???????.

GradleisBetTerChoiceFormostNewProjectSduetoitssuperiorflexible, Performance, and ModernToolingsupport.1.Gradle'Sgroovy/kotlindslismoreConcisENDEXPRESSIVETHANMAVEN'SVOSEXML.2.GradleOutsMaveninbuildweedweedweedweedweedweedweedweedweedweedweedweedweedweede

DEFER? ??? ???? ?? ??? ??? ???? ? ?????. ?? ??? ?? ? ? ?? ????, ??? ??? ? ?? ?? (LIFO)? ??? ?????. 1. ?? ??? ??? ? ??? ?????. 2. ?? ??? ?? ??? ??? ????? ?????. 3. ?? ? ?? ?? ??? ? ????. 4. ??? ?????? ??? ??? ???? ?????. 5. ?? ??? ???? ?? ??? ?? ??? ?????. ??? ??? ?? ?? ? ???? ???? ? ????.
