Java: 根據網易雲音樂URL下載歌曲、歌詞、專輯封面和MV
阿新 • • 發佈:2019-02-10
先看最終效果圖:
前提請下載:
(1)jsoup-1.11.3.jar
(2)JMF 2.1.1e
然後使用開源的JSoup分析框架原始碼得到如下:
<script type="application/ld+json"> { "@context": "https://ziyuan.baidu.com/contexts/cambrian.jsonld", "@id": "http://music.163.com/song?id=5048563", "appid": "1582028769404989", "title": "I'll Be There For You", "images": ["http://p1.music.126.net/DOjgC0ig0QrOD67aJM5kGg==/2532175279901155.jpg"], "description": "歌手:The Rembrandts。所屬專輯:Friends。", "pubDate": "2005-10-01T00:00:00" } </script>
以及:
<a title="播放mv" href="/mv?id=5361246"><i class="icn u-icn u-icn-2"></i></a>
這樣,就獲得了該音樂的基礎資訊和MV地址(如果有MV的話)
比較重要的網址如下(外鏈MP3):
用Java下載檔案即可。同理下載專輯封面和MV也是如此分析。
獲取歌詞網址如下:
這樣就獲得了歌詞。如果有LRC歌詞,則預設顯示LRC,否則是普通歌詞,否則沒有歌詞(暫無或純音樂)。
例項歌詞如下:
{"songStatus":3,"lyricVersion":9,"lyric":"[00:11.780]So no one told you life was gonna be this way:\n[00:15.920]your jobs a joke, you're broke, your love life's D.O.A.\n[00:20.880]It's like you're always stuck in second gear,\n[00:24.980]And it hasn't been your day, your week, your month, or even your year, but\n[00:30.660]I'll be there for you, when the rain starts to pour\n[00:35.590]I'll be there for you, like I've been there before\n[00:40.690]I'll be there for you, 'cause you're there for me too.\n[00:48.260]You're still in bed at ten and work began at eight\n[00:53.220]You've burned your breakfast, so far things are goin' great.\n[00:59.120]Your mother warned you there'd be days like these\n[01:03.450]Oh but she didn't tell you when the world has brought you down to your knees that\n[01:09.160]I'll be there for you, when the rain starts to pour\n[01:14.200]I'll be there for you, like I've been there before\n[01:18.300]I'll be there for you, 'cause you're there for me too.\n[01:28.350]No one could ever know me, no one could ever see me\n[01:35.190]Seems you're the only one who knows what it's like to be me.\n[01:40.250]Someone to face the day with, make it through all the rest with\n[01:46.960]Someone I'll always laugh with, even at my worst I'm best with you, yeah.\n[02:12.100]It's like you're always stuck in second year\n[02:16.300]And it hasn't been your day, your week, your month, or even your year.\n[02:23.340]I'll be there for you, when the rain starts to pour\n[02:28.340]I'll be there for you, like I've been there before\n[02:32.260]I'll be there for you, 'cause you're there for me too.\n[02:41.010]I'll be there for you, I'll be there for you,\n[02:50.870]I'll be there for you 'cause you're there for me too...\n[02:57.580]How you doin'?\n[02:58.580]\n","code":200}
需要注意的是,歌詞裡可能會顯示“\n”或者"\r",此時就需要String.format()轉換格式或將"\\r\\n"轉換成"\r\n",以便儲存到檔案裡。(慶祝微軟記事本重大升級)
適當修改格式即可正常顯示。效果如下:
選擇適當選項即可下載。下載後:
剩下附加的諸多功能就不說了。關鍵程式碼如下:
HTTPAnalyzer.java
// Coding starts here // Version 3.0 專用 import java.io.IOException; import org.jsoup.Jsoup; // jsoup-1.11.3 /** * HTTPAnalyzer類。分析網頁框架,獲得有用資訊 * @author 趙利昂 * @since 0.5 */ public class HTTPAnalyzer { private String myURL = ""; // 使用者輸入的URL地址 private String URL_id = ""; // 解析得到的ID private String frameURL = ""; // 網頁框架地址 private String bodyCode = ""; // 框架原始碼 private String essentialPart = ""; // 用於分析資料的部分 private String info[]; // 歌曲資訊 private String lrc; // LRC歌詞(帶時間標籤,可能無歌詞,需要去MainFrame判斷) private String lrcUrl; // LRC歌詞地址 private boolean hasMV = false; private String mvUrl = "NULL"; // MV地址(若無則返回“NULL”) /** * 獲取URL框架中有用的資訊 * @param myURL 要分析的URL * @throws IOException */ public HTTPAnalyzer(String myURL) throws IOException { MainFrame.logEvent("嘗試解析網頁框架地址"); if(myURL.toLowerCase().startsWith("music.163")) this.myURL = "http://" + myURL; else this.myURL = myURL; this.URL_id = myURL.substring(myURL.lastIndexOf("song?id=") + 8); this.frameURL = "http://music.163.com/song?id=" + this.URL_id; this.bodyCode = Jsoup.connect(this.frameURL).timeout(3000).execute().body(); this.essentialPart = bodyCode.substring( bodyCode.indexOf("<script type=\"application/ld+json\">"), bodyCode.indexOf("<script type=\"text/javascript\">")); this.lrcUrl = "http://music.163.com/api/song/media?id=" + URL_id; int[] pos = new int[7]; pos[0] = this.essentialPart.indexOf("\"@context\": \""); pos[1] = this.essentialPart.indexOf("\"appid\": \""); pos[2] = this.essentialPart.indexOf("\"title\": \""); pos[3] = this.essentialPart.indexOf("\"images\": [\""); pos[4] = this.essentialPart.indexOf("\"description\": \"歌手:"); pos[5] = this.essentialPart.indexOf("。所屬專輯:"); pos[6] = this.essentialPart.indexOf("\"pubDate\": \""); String[] substrings = new String[7]; substrings[0] = this.essentialPart.substring(pos[0]); substrings[1] = this.essentialPart.substring(pos[1]); substrings[2] = this.essentialPart.substring(pos[2]); substrings[3] = this.essentialPart.substring(pos[3]); substrings[4] = this.essentialPart.substring(pos[4]); substrings[5] = this.essentialPart.substring(pos[5]); substrings[6] = this.essentialPart.substring(pos[6]); /* * info[0]: context <!-- @URL --> * info[1]: appid * info[2]: title * info[3]: images <!-- @URL --> * info[4]: artist * info[5]: album * info[6]: pubDate */ MainFrame.logEvent("嘗試返回解析內容到本地"); this.info = new String[7]; this.info[0] = substrings[0].substring(13, substrings[0].indexOf("\",")); this.info[1] = substrings[1].substring(10, substrings[1].indexOf("\",")); this.info[2] = substrings[2].substring(10, substrings[2].indexOf("\",")); this.info[3] = substrings[3].substring(12, substrings[3].indexOf("\"],")); this.info[4] = substrings[4].substring(19, substrings[4].indexOf("。")); this.info[5] = substrings[5].substring(6, substrings[5].indexOf("。\",")); this.info[6] = substrings[6].substring(12, substrings[6].length() - 14); int mvStart = bodyCode.indexOf("<a title=\"播放mv\" href=\"/mv?id="); if(mvStart != -1) { hasMV = true; String mvEssential = bodyCode.substring(mvStart, bodyCode.indexOf("\"><i class=\"icn u-icn u-icn-2\"></i>", mvStart)); this.mvUrl = "http://music.163.com/mv?id=" + mvEssential.substring(29); String downloadMvEssential = Jsoup.connect(this.mvUrl).timeout(100000).execute().body(); String actualMvUrl = downloadMvEssential.substring( downloadMvEssential.indexOf("http%3A%2F%2Fv4.music.126.net"), downloadMvEssential.indexOf(".mp4\"")); MainFrame.actualDownloadMVURL = actualMvUrl.replace("%3A", ":").replace("%2F", "/").replace("%3D", "=") + ".mp4"; } else { hasMV = false; this.mvUrl = "NULL"; MainFrame.actualDownloadMVURL = "NULL"; } MainFrame.logEvent("嘗試獲取歌詞主體"); this.lrc = Jsoup.connect(this.lrcUrl).timeout(3000).execute().body(); } public String getEssentialPart() { return this.essentialPart; } public String getMyURL() { return myURL; } public String getURL_id() { return URL_id; } public String getFrameURL() { return frameURL; } public String getBodyCode() { return bodyCode; } public String[] getInfoArray() { return info; } public String getLrc() { return lrc; } public String getLrcUrl() { return lrcUrl; } public boolean hasMusicVideo() { return hasMV; } public String getMvUrl() { return mvUrl; } @Override public String toString() { return "[Analytic result]\r\nContext: " + info[0] + "\r\n" + "AppID: " + info[1] + "\r\n" + "Title: " + info[2] + "\r\n" + "Album_img: " + info[3] + "\r\n" + "Artist: " + info[4] + "\r\n" + "Album: " + info[5] + "\r\n" + "PublishedDate:" + info[6] + "\r\n" + "HasMV: " + hasMV + "\r\n" + "MVURL: " + mvUrl; } }
這是整個軟體很小的一部分,但卻是最重要的一部分(MainFrame.logEvent()只是我用於記錄軟體活動的方法)。軟體需要繼續維護和升級,還要加入很多新的功能(比如暫時設想的:獲取高清或其他解析度的MV地址,生成歌手資訊,獲取同一張專輯中其他歌曲等),其餘程式碼就不公開了。
注:帶有版權問題的歌曲是不能下載的,畢竟又不是百度網盤(哦呵呵呵呵呵呵呵呵呵呵呵呵呵呵呵呵)
在進階的路上,歡迎各位大俠指正。