網易雲歌詞爬取(java)

antoneo發表於2018-07-01

網上也有很多人寫過的,但感覺可能都不是很細,特此寫了一份,不足之處請大家多多包涵 就以這首<涼涼>為例,給大家分享一下網易雲歌詞的獲取

歌曲地址:https://music.163.com/#/song?id=536622115

F12找到歌詞的請求地址

0
通過觀察可以發現就是這params和encSecKey不知道怎麼來的 別急!肯定是js算出來的,慢慢從找 將encSecKey引數放到請求的js檔案裡面檢索就能發現下面這個,大致鎖定就在這了
1
好了,去source裡面找到這個js我們打個斷點 我這裡的請求url變數是Y0x,要觀察這個值,目前我們是去抓取歌詞,所以其他的請求我們都跳過,直到 Y0x=“/api/song/lyric”,如下圖所示
2
當執行到下圖所示時,
3
現在來分析下 主要關注的

var bRB0x = window.asrsea(JSON.stringify(i9b), brX3x(["流淚", "強"]), brX3x(Ua6U.md), brX3x(["愛心", "女孩", "驚恐", "大笑"]));
複製程式碼

i9b我們已知了

i9b={
  id : "536622115",//需要關注的就是你了,這個值就是歌曲的id值
  lv : -1,
  tv :-1,
  csrf : ""
}
複製程式碼

brX3x(["流淚", "強"] brX3x(Ua6U.md) brX3x(["愛心", "女孩", "驚恐", "大笑"]) 這三個值,都是固定的,這個暫時不需要過多的關注,先把他們的值給記一下

brX3x(["流淚", "強"]="010001"
brX3x(Ua6U.md)="00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
brX3x(["愛心", "女孩", "驚恐", "大笑"])="0CoJUm6Qyw8W8jud"
複製程式碼

繼續去看看window.asrsea(),這個方法裡面做了啥子

4
執行的是這個function d

function d(d, e, f, g) {
        var h = {}
          , i = a(16);
        return h.encText = b(d, g),
        h.encText = b(h.encText, i),
        h.encSecKey = c(i, e, f),
        h
    }
複製程式碼

這四個值我們也已經得知了, i=a(16),仔細看a(16)好像就是個隨機數,先不管 h.encText = b(d, g) d,g我們都知道了,d就是有歌曲id的json,g是brX3x(["愛心", "女孩", "驚恐", "大笑"])是個固定值

d="{"id" : "536622115","lv ": -1,"tv" :-1,"csrf" : ""}
g="0CoJUm6Qyw8W8jud"
複製程式碼

接下來看看h.encText = b(d, g)這個,AES加密,iv值是固定寫死的,這個好辦用java去寫個AES加密

package com.dcs.common.utils;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * AES 是一種可逆加密演算法,對使用者的敏感資訊加密處理
 * 對原始資料進行AES加密後,在進行Base64編碼轉化;
 * @author Antoneo
 * @create 2018-06-28 22:16
 **/
public class AesCBCUtils {
    /**
     * 加密用的Key 可以用26個字母和數字組成
     * 此處使用AES-128-CBC加密模式,key需要為16位。
     */



    /**
     * 加密
     * @param sSrc              明文
     * @param encodingFormat    字符集
     * @param sKey              祕鑰
     * @param ivParameter       向量iv
     * @return
     * @throws Exception
     */
    public static String encrypt(String sSrc, String encodingFormat, String sKey, String ivParameter) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] raw = sKey.getBytes();
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes());//使用CBC模式,需要一個向量iv,可增加加密演算法的強度
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
        byte[] encrypted = cipher.doFinal(sSrc.getBytes(encodingFormat));
        return new BASE64Encoder().encode(encrypted);//此處使用BASE64做轉碼。
    }


    /**
     * 解密
     * @param sSrc              明文
     * @param encodingFormat    字符集
     * @param sKey              祕鑰
     * @param ivParameter       iv向量
     * @return
     * @throws Exception
     */
    public static String decrypt(String sSrc, String encodingFormat, String sKey, String ivParameter) throws Exception {
        try {
            byte[] raw = sKey.getBytes("ASCII");
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes());
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
            byte[] encrypted1 = new BASE64Decoder().decodeBuffer(sSrc);//先用base64解密
            byte[] original = cipher.doFinal(encrypted1);
            String originalString = new String(original,encodingFormat);
            return originalString;
        } catch (Exception ex) {
            return null;
        }
    }


    public static void main(String[] args) throws Exception {
        String a=encrypt("{"id":"536622115","lv":-1,"tv":-1,"csrf_token":""}","utf-8","0CoJUm6Qyw8W8jud","0102030405060708");
        System.out.println(a);
    }

}

複製程式碼

執行下看看

5
沒問題,java和js執行結果一致 接著往下看 h.encText = b(h.encText, i),又來一遍,i的值a(16)就把他當成一個固定值

a(16)="Sx7KnWt4ttr85X0b"
複製程式碼

往下走

h.encSecKey = c(i, e, f)
function c(a, b, c) {
        var d, e;
        return setMaxDigits(131),
        d = new RSAKeyPair(b,"",c),
        e = encryptedString(d, a)
    }
複製程式碼

在這個c方法裡面, a就是傳過來i也就是a(16), b就是brX3x(["流淚", "強"], c就是brX3x(Ua6U.md),

a="Sx7KnWt4ttr85X0b"
b="010001"
c="00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
複製程式碼

慢點...仔細想想好像有點貓膩呢 a是隨機值,可以理解成固定值,b和c都是固定值 .... 這就歡快了,理一下思路 這就是說只要這個a(16)這個隨機值不變,那個c的結果是固定的,就是encSecKey是固定的(js執行下檢視結果就ok了); 已知a(16),寫好的AES加密已經可以把encText的值給算出來了 好像已經結束了 。。。。(≧∇≦)ノ

encText="+o2ZcetTMTEWY1KLilzaGDKZwZ4dAgEZ+xke0FxnHcGs9TlVM91xyVhOZWc5Xe1aoHUQdMESSdOv
yeYQZ1K02Q=="
encSecKey="252e2abdc25a5c8e4e4131b88db3df7d01ab4a139249b78e653b97ab52f53b873993b86648e54daa3a99eeb20fd3b2c4d1d551231a152bfa56ed0a13baae9243f978bf1fbcde4e70b25087fd0aeef413a698a0a37567a550876f8cdeedb25cf359f54532eb2681f63641a4fa98b837fb9978c3296b2923bca8f5d1661d3ec5dc"
複製程式碼

去驗證一下吧 程式碼都放出來: AesCBCUtils.java

package com.dcs.common.utils;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * AES 是一種可逆加密演算法,對使用者的敏感資訊加密處理
 * 對原始資料進行AES加密後,在進行Base64編碼轉化;
 * @author Antoneo
 * @create 2018-06-28 22:16
 **/
public class AesCBCUtils {
    /**
     * 加密用的Key 可以用26個字母和數字組成
     * 此處使用AES-128-CBC加密模式,key需要為16位。
     */



    /**
     * 加密
     * @param sSrc              明文
     * @param encodingFormat    字符集
     * @param sKey              祕鑰
     * @param ivParameter       向量iv
     * @return
     * @throws Exception
     */
    public static String encrypt(String sSrc, String encodingFormat, String sKey, String ivParameter) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] raw = sKey.getBytes();
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes());//使用CBC模式,需要一個向量iv,可增加加密演算法的強度
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
        byte[] encrypted = cipher.doFinal(sSrc.getBytes(encodingFormat));
        return new BASE64Encoder().encode(encrypted);//此處使用BASE64做轉碼。
    }


    /**
     * 解密
     * @param sSrc              明文
     * @param encodingFormat    字符集
     * @param sKey              祕鑰
     * @param ivParameter       iv向量
     * @return
     * @throws Exception
     */
    public static String decrypt(String sSrc, String encodingFormat, String sKey, String ivParameter) throws Exception {
        try {
            byte[] raw = sKey.getBytes("ASCII");
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes());
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
            byte[] encrypted1 = new BASE64Decoder().decodeBuffer(sSrc);//先用base64解密
            byte[] original = cipher.doFinal(encrypted1);
            String originalString = new String(original,encodingFormat);
            return originalString;
        } catch (Exception ex) {
            return null;
        }
    }


    public static void main(String[] args) throws Exception {
        String a=encrypt("{\"id\":\"536622115\",\"lv\":-1,\"tv\":-1,\"csrf_token\":\"\"}","utf-8","0CoJUm6Qyw8W8jud","0102030405060708");
        System.out.println(a);
    }

}

複製程式碼

WyyParams.java

package com.dcs.spider.wyy;

import lombok.Data;

/**
 * 引數
 *
 * @author Antoneo
 * @create 2018-06-28 22:46
 **/
@Data
public class WyyParams {

    private String encText;
    private String encSecKey;
}

複製程式碼

WyySpider.java

package com.dcs.spider.wyy;

import com.dcs.common.utils.AesCBCUtils;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

import java.util.HashMap;
import java.util.Map;

/**
 * 網易雲抓取
 *
 * @author Antoneo
 * @create 2018-06-28 22:21
 **/
public class WyySpider {

    private static String iv="0102030405060708";
    private static String g="0CoJUm6Qyw8W8jud";
    private static String i="Sx7KnWt4ttr85X0b";
    private static String encSecKey="252e2abdc25a5c8e4e4131b88db3df7d01ab4a139249b78e653b97ab52f53b873993b86648e54daa3a99eeb20fd3b2c4d1d551231a152bfa56ed0a13baae9243f978bf1fbcde4e70b25087fd0aeef413a698a0a37567a550876f8cdeedb25cf359f54532eb2681f63641a4fa98b837fb9978c3296b2923bca8f5d1661d3ec5dc";


    private static String a(int a){
        int d,e;
        String b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        String c="";
        for(d=0;a>d;d+=1){
            e=(int)Math.floor(Math.random()*b.length());
            c+=b.charAt(e);
        }
        return c;
    }

    private static String b(String d,String g) throws Exception {
        return AesCBCUtils.encrypt(d,"utf-8",g,iv).replace("\r\n","");
    }


    /**
     * 獲得歌詞url的引數物件
     */
    public static WyyParams getParams(String id) throws Exception {
        String d=String.format("{\"id\":\"%s\",\"lv\":-1,\"tv\":-1,\"csrf_token\":\"\"}",id);
        String encText=b(d,g);
        encText=b(encText,i);
        WyyParams params=new WyyParams();
        params.setEncSecKey(encSecKey);
        params.setEncText(encText);
        return params;
    }

    public static Document spider(String id){
        Document doc= null;
        Map data=new HashMap();
        Map head=new HashMap();
        try {
            WyyParams params=WyySpider.getParams(id);
            Connection con=Jsoup.connect("https://music.163.com/weapi/song/lyric?csrf_token=");
            data.put("encSecKey",params.getEncSecKey());
            data.put("params",params.getEncText());
            head.put("Content-Type","application/x-www-form-urlencoded");
            head.put("Accept","*/*");
            con.headers(head);
            con.data(data);
            doc= con.post();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return doc;
    }


    public static void main(String[] args){
        String id ="536622115";
        Document doc=WyySpider.spider(id);
        if(null!=doc) {
            System.out.println(doc.text());
        }
    }
}


複製程式碼

執行結果:

{"sgc":true,"sfy":false,"qfy":false,"lrc":{"version":4,"lyric":"[00:00.00] 作曲 : 譚旋\n[00:01.00] 作詞 : 劉暢\n[00:03.19]編曲Arranger:尼克Ke Ni\n[00:04.41]製作人Producer:張梓軒Zixuan Zhang/倪睿思 Ruisi Ni\n[00:05.76]原唱Original Singer:張碧晨Bichen Zhang /楊宗緯Zongwei Yang\n[00:07.01]音樂總監Music director:樑翹柏Kubert Leung\n[00:08.32]混音Mixing Engineer:林夢洋Mengyang Lin\n[00:09.59]鍵盤Keyboard players:達日丹Ridan Da/楊陽Yang Yang/白宇軒Yuxuan Bai\n[00:10.96]貝斯Bassist:韓陽Yang Han\n[00:12.30]吉他Guitarist:Tommy /黃仲賢Zhongxian Huang\n[00:13.70]鼓Drummer:郝稷倫Jilun Hao\n[00:15.03]小號Trumpet Player:Ray\n[00:16.36]打擊樂Percussionist:劉效鬆Xiaosong Liu\n[00:17.73]薩克斯/單簧管Saxes Player/Clarinet Player:Miles\n[00:19.01]薩克斯/長笛Saxes Player/Flute Player:Charlie\n[00:20.43]長號Trombone Player:謝燕輝Yanhui Xie\n[00:21.77]絃樂String Orchestra:靳海音®絃樂團 Jin HaiYin®String orchestra\n[00:23.18]和聲Harmonic Orchestra:愛之音合音組Sound of love Chorus group\n[00:24.49]\n[00:37.04]女:\n[00:42.91]入夜漸微涼\n[00:44.90]繁花落地成霜\n[00:47.54]你在遠方眺望\n[00:50.16]耗盡所有暮光\n[00:52.88]不思量自難相忘\n[01:02.96]\n[01:03.68]男:\n[01:04.22]夭夭桃花涼\n[01:06.16]前世你怎舍下\n[01:08.80]這一海心茫茫\n[01:11.51]還故作不痛不癢不牽強\n[01:18.11]都是假象\n[01:24.17]\n[01:24.65]女:\n[01:25.22]涼涼夜色為你思念成河\n[01:30.66]化作春泥呵護著我\n[01:35.20]\n[01:35.67]男:\n[01:35.85]淺淺歲月拂滿愛人袖\n[01:40.45]片片芳菲入水流\n[01:46.44]\n[01:46.82]女:\n[01:47.11]涼涼天意瀲灩一身花色\n[01:51.67]落入凡塵傷情著我\n[01:56.74]\n[01:57.02]男:\n[01:57.36]生劫易渡情劫難了\n[02:00.29]折舊的心還有幾分前生的恨\n[02:08.04]還有幾分\n[02:10.98]\n[02:11.39]女:\n[02:11.89]前生的恨\n[02:20.94]\n[02:35.51]女:\n[02:37.11]也曾鬢微霜\n[02:39.46]也曾因你回光\n[02:41.96]悠悠歲月漫長\n[02:44.69]怎能浪費時光\n[02:47.36]去流浪\n[02:51.73]去換成長\n[02:56.40]\n[02:57.69]男:\n[02:58.67]灼灼桃花涼\n[03:00.75]今生愈漸滾燙\n[03:03.32]一朵已放心上\n[03:06.05]足夠三生三世背影成雙\n[03:10.63]\n[03:10.82]女:\n[03:11.09]背影成雙\n[03:13.05]\n[03:13.46]男:\n[03:13.73]在水一方\n[03:17.91]\n[03:18.41]女:\n[03:19.91]涼涼夜色為你思念成河\n[03:25.21]化作春泥呵護著我\n[03:30.11]\n[03:30.42]男:\n[03:30.74]淺淺歲月拂滿愛人袖\n[03:35.17]片片芳菲入水流\n[03:41.06]\n[03:41.36]女:\n[03:41.63]涼涼天意瀲灩一身花色\n[03:46.47]落入凡塵傷情著我\n[03:51.41]\n[03:51.75]男:\n[03:52.07]生劫易渡情劫難了\n[03:54.85]折舊的心還有\n[03:57.26]\n[03:57.55]合:\n[03:57.76]幾分前生的恨\n[04:03.49]\n[04:12.95]女:\n[04:13.60]涼涼三生三世恍然如夢\n[04:18.45]須臾的年風乾淚痕\n[04:23.38]\n[04:23.71]男:\n[04:24.05]若是回憶不能再相認\n[04:28.31]\n[04:28.65]合:\n[04:28.82]就讓情分落九塵\n[04:34.26]\n[04:34.50]女:\n[04:34.83]涼涼十里何時還會春盛\n[04:39.73]又見樹下一盞風存\n[04:44.65]\n[04:45.04]男:\n[04:45.34]落花有意流水無情\n[04:48.25]別讓恩怨愛恨\n[04:50.62]\n[04:50.81]合:\n[04:50.98]涼透那花的純\n[04:57.83]\n[04:58.29]女:\n[04:58.87]吾生願牽塵\n[05:11.19]\n"},"tlyric":{"version":0,"lyric":null},"code":200}

Process finished with exit code 0

複製程式碼

換首歌再試一遍: https://music.163.com/#/song?id=863492743 執行結果:

{"sgc":true,"sfy":true,"qfy":true,"lrc":{"version":4,"lyric":"[00:00.00] 作曲 : 陳壹千\n[00:01.00] 作詞 : 陳壹千\n[00:10.629]混音:陳壹千\n[00:17.695]終於還是沒能等到結果\n[00:22.696]謊言將我淹沒\n[00:25.505]偽裝的人不是我\n[00:30.111]還傻傻的難過 以為你會懂\n[00:35.341]我才讓你解剖\n[00:37.709]所有一切都因為你變得刺痛\n[00:45.398]終於還是下定決心走得乾淨利落\n[00:50.702]倒不如離開有你的地方\n[00:54.573]去別的城市找回我\n[00:58.213]都怪我太念舊\n[01:01.631]而你太過刻薄\n[01:03.717]從那以後\n[01:06.133]我學會了讓眼淚偷偷的 往回流\n[01:17.541]還是回到了我們開始的地方\n[01:23.646]我們都只看到期待 卻都忘了要等待\n[01:31.589]那種孩子理念在現實裡面\n[01:35.645]最多撐不過一年\n[01:38.639]在有限時間打破所有的誓約\n[01:45.509]我現在才懂得一個人可以很快樂\n[01:52.653]雖然還會輾轉反側 想起時眼眶會熱\n[01:59.463]而你早已忘了關於我的 好的壞的\n[02:07.189]在我離開以後\n[02:15.893]這次真的可以還你自由\n[02:19.977]我想分開會好過互相折磨\n[02:27.039]我還是習慣開著燈 熬到凌晨\n[02:32.366]就算睡著也不害怕\n[02:35.873]不如當作有個人在黑夜裡陪我\n[02:42.066]我終於下定決心刪除所有你的段落\n[02:48.480]也留一點尊嚴給自己以後見到你時不回頭\n[02:55.623]我真的不在乎\n[02:58.975]但有時候卻又控制不住\n[03:03.906]一點遺憾 也有一點不甘\n[03:11.610]還是回到了我們開始的地方\n[03:18.185]我們都只看到期待 卻都忘了要等待\n[03:24.833]那種孩子理念在現實裡面\n[03:29.401]最多撐不過一年\n[03:32.744]在有限時間打破所有的誓約\n[03:39.559]我現在才懂得一個人可以很快樂\n[03:46.593]雖然還會輾轉反側 想起時眼眶會熱\n[03:53.240]而你早已忘了關於我的 好的壞的甜的苦的\n[04:01.426]在我離開你的城市以後\n[04:08.199]我不會再哭著求你為我最後一次擦眼淚\n[04:22.159]也在盡力忘了關於你的\n[04:26.264]只是想起時心有點疼\n"},"tlyric":{"version":0,"lyric":null},"code":200}

Process finished with exit code 0

複製程式碼

網易雲的歌詞獲取到此結束了,教大家方法後可以用來獲取網易雲評論或者其他的什麼 第一次寫文章有點小激動... 謝謝支援!

簡書地址: https://www.jianshu.com/p/c1595cbb11df

相關文章