网易云音乐爬虫

因最近写了一了音乐播放器 , 所以对各大知名音乐网站都写了爬虫程序 , 接下来我会将我的所有爬虫程序写成博客 , 学识有限,有些地方可能表述的不够准确 , 望大佬见谅

由于最近在学PHP , 所以代码先由PHP实现 , 有时间我会将java , python的实现代码贴出来 , 好了下面进入正题

首先打开网易云音乐网站 , 右键检查 , 进入network 然后刷新页面
在这里插入图片描述
这个文件是获取音乐地址的关键文件在这里插入图片描述
打开请求发现 , 它是一个post请求而且参数进行了加密 没办法只有去看网易云的js文件了 检索encSecKey 发现关键代码在 下面这个文件中(这个地址经常改变,可能你的已经不是这一个了)https://s3.music.126.net/web/s/core_a5deb939c48df9f196db7386e2a72233.js?a5deb939c48df9f196db7386e2a72233

进行格式化一下将关键代码找出来

function() {
    function a(a) {
        var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
        c = "";
        for (d = 0; a > d; d += 1) e = Math.random() * b.length,
        e = Math.floor(e),
        c += b.charAt(e);
        return c
    }
    function b(a, b) {
        var c = CryptoJS.enc.Utf8.parse(b),
        d = CryptoJS.enc.Utf8.parse("0102030405060708"),
        e = CryptoJS.enc.Utf8.parse(a),
        f = CryptoJS.AES.encrypt(e, c, {
            iv: d,
            mode: CryptoJS.mode.CBC
        });
        return f.toString()
    }
    function c(a, b, c) {
        var d, e;
        return setMaxDigits(131),
        d = new RSAKeyPair(b, "", c),
        e = encryptedString(d, a)
    }
    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
    }
    function e(a, b, d, e) {
        var f = {};
        return f.encText = c(a + e, b, d),
        f
    }
    window.asrsea = d,
    window.ecnonasr = e
}

开始这段代码我看的很头疼 , 能力有限根本看不出来这段代码的执行流程 , 于是我借助fiddler工具将网易云的这个文件替换成本地的一个文件了 , 本地代码 :

function() {
    function a(a) {
        console.log("a函数进入 a => " + a);
        var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
        c = "";
        for (d = 0; a > d; d += 1) e = Math.random() * b.length,
        e = Math.floor(e),
        c += b.charAt(e);
        return c
    }
    function b(a, b) {
        console.log("b函数进入 a => " + a + "  b=>" + b);
        var c = CryptoJS.enc.Utf8.parse(b),
        d = CryptoJS.enc.Utf8.parse("0102030405060708"),
        e = CryptoJS.enc.Utf8.parse(a),
        f = CryptoJS.AES.encrypt(e, c, {
            iv: d,
            mode: CryptoJS.mode.CBC
        });
        return f.toString()
    }
    function c(a, b, c) {
        console.log("c函数进入 a => " + a + "  b=>" + b + " c=>" + c);
        var d, e;
        return setMaxDigits(131),
        d = new RSAKeyPair(b, "", c),
        e = encryptedString(d, a)
    }
    function d(d, e, f, g) {
        console.log("d函数进入 d => " + d + "  e=>" + e + " f=>" + f + "  g=>" + 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
    }
    function e(a, b, d, e) {
        console.log("e函数进入 a => " + a + "  b=>" + b + " d=>" + d + "  e=>" + e);
        var f = {};
        return f.encText = c(a + e, b, d),
        f
    }
    window.asrsea = d,
    window.ecnonasr = e
}

每个函数里面都加了一个输出 , 然后清除一下浏览器缓存 , 再刷新网易云的网站 , 然后看控制台输出

d函数进入 d => {"ids":"[1336866698]","br":128000,"csrf_token":""}  e=>010001 f=>00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7  g=>0CoJUm6Qyw8W8jud
core_a5deb939c48df9f196db7386e2a72233.js?a5deb939c48df9f196db7386e2a72233:88 
a函数进入 a => 16
core_a5deb939c48df9f196db7386e2a72233.js?a5deb939c48df9f196db7386e2a72233:88 
b函数进入 a => {"ids":"[1336866698]","br":128000,"csrf_token":""}  b=>0CoJUm6Qyw8W8jud
core_a5deb939c48df9f196db7386e2a72233.js?a5deb939c48df9f196db7386e2a72233:88 
b函数进入 a => NwoJca234EubXlkdSucwDVGT31vu5v2R1Kc1OhMC8VHhHWkT3h8b1ONNSns/t0KwXJ3Nnj17GnXlNqdbYdp+YQ==  b=>cui5UlB0Hp5Osovk
core_a5deb939c48df9f196db7386e2a72233.js?a5deb939c48df9f196db7386e2a72233:88 
c函数进入 a => cui5UlB0Hp5Osovk  b=>010001 c=>00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7

encSecKey:"b62d8aeac7f4cd0a2653997c76ec40103504a6b3ccd6df45230ba0c9ffba53f21574676726c37a4c3910d394e21e9a71604b084f4e1105d6c4db7e7da1af9d4e2357fb80ebcdeb13d8bc268288a5d9ae23bec681c1f15fa7eb9a03c9229e9a94efd887e46b332f4c3421567bf9236cf847cd7708b4d39a03bff95cb194879635"
encText:"EPNWe5sbpNdQdH4pQGiu97wnuMUeIr4FmICM17IfGQE18M0vYINPrjrKOuoA9NjL8O9uVZIV/+rrWIVNSMr89khB7y4H//GtO7JHwG4azP6ZWmAf4Ge4W6+eDQc7vm9r"

首先进入d函数 , 你多刷新几遍会发现d函数除了第一个参数后面三个参数都是死的 , 进行了两次b函数加密出params参数 b函数是AES加密 他的秘钥有一个是a函数生成的 另外几个秘钥都是死的, 进行一次c函数加密出encSecKey参数

因为我对加密的了解不多 , 对我来说要模拟出c函数很困难,所以从加密这条路我已经走不通了 , 那我就从服务器解密来逆向思考一下

首先他要给用户返回正确信息他就必须要解密出params参数 ,那么就得获取加密的秘钥 , 不难知道加密秘钥就藏在encSecKey中 , 所以我只要保证 加密params时的秘钥与encSecKey为一套就行了

例如:
我就用上面那个c函数的a参数cui5UlB0Hp5Osovk作为加密params的秘钥
encSecKey就用刚刚生成的b62d8aeac7f4cd0a2653997c76ec40103504a6b3ccd6df45230ba0c9ffba53f21574676726c37a4c3910d394e21e9a71604b084f4e1105d6c4db7e7da1af9d4e2357fb80ebcdeb13d8bc268288a5d9ae23bec681c1f15fa7eb9a03c9229e9a94efd887e46b332f4c3421567bf9236cf847cd7708b4d39a03bff95cb194879635

经过这样一分析发现除了进入d函数的第一个参数是活的其他的都是死的 , encSecKey就使用上面这一个 , 我们只要以cui5UlB0Hp5Osovk作为秘钥生成params参数就行了

好了分析就到此结束 , 下面上代码 (以PHP为例)

define("PARAME1" , "0CoJUm6Qyw8W8jud"); #相当于进入d函数的参数g
define("PARAME2" , "0102030405060708");    #b函数中的一个死的秘钥
$songData = '{"ids":"[1316563155]","br":128000,"csrf_token":""}' ; #歌曲信息
//模拟浏览器访问头
$header = array(
    'Referer'         => 'https://music.163.com/',
    'User-Agent'      => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/605.1.15 (KHTML, like Gecko)'
);
//将参数格式化
$header = array_map(function($k,$v){
    return $k.": ".$v ;
} , array_keys($header) , $header);
//a函数生成的秘钥我写死为它了
$a_back = "cui5UlB0Hp5Osovk" ;
//进行一次AES加密
$songData = openssl_encrypt($songData, 'aes-128-cbc', PARAME1 , false, PARAME2);
//进行两次加密
$params   = openssl_encrypt($songData, 'aes-128-cbc', $a_back , false, PARAME2);
//encSecKey 我也写死 , 只要保证他和上面 $a_back一致就行了
$encSecKey = "b62d8aeac7f4cd0a2653997c76ec40103504a6b3ccd6df45230ba0c9ffba53f21574676726c37a4c3910d394e21e9a71604b084f4e1105d6c4db7e7da1af9d4e2357fb80ebcdeb13d8bc268288a5d9ae23bec681c1f15fa7eb9a03c9229e9a94efd887e46b332f4c3421567bf9236cf847cd7708b4d39a03bff95cb194879635" ;
//下面是curl的使用
$curl = curl_init("https://music.163.com/weapi/song/enhance/player/url?csrf_token=");

curl_setopt($curl , CURLOPT_HEADER , false);
curl_setopt($curl , CURLOPT_SSL_VERIFYPEER , false);
curl_setopt($curl , CURLOPT_RETURNTRANSFER , true);
curl_setopt($curl , CURLOPT_POST , true);
curl_setopt($curl , CURLOPT_HTTPHEADER , $header);
curl_setopt($curl , CURLOPT_POSTFIELDS , http_build_query(array("params" => $params , "encSecKey" => $encSecKey)));

$response = curl_exec($curl);

echo $response;

运行结果:
{
“data”: [{
“id”: 1316563155,
“url”: “http://m10.music.126.net/20190219121104/8ef5afe8bf60107442da3b392a85d853/ymusic/14c4/c25d/c027/5fdbf1159c6191ed158af3788b79cd52.mp3”,
“br”: 128000,
“size”: 3306519,
“md5”: “5fdbf1159c6191ed158af3788b79cd52”,
“code”: 200,
“expi”: 1200,
“type”: “mp3”,
“gain”: 0.3218,
“fee”: 0,
“uf”: null,
“payed”: 0,
“flag”: 0,
“canExtend”: false,
“freeTrialInfo”: null
}],
“code”: 200
}

好了我知道的就这么多了 , 希望可以帮助到你
我的GitHub:https://github.com/wangffei/PHP , 里面有更详细的代码

猜你喜欢

转载自blog.csdn.net/weixin_43999566/article/details/87697962