一、 前言
先说结论,目前无法下载无损音乐,也无法下载vip音乐。
此代码模拟web网页js加密的过程,向api接口发送参数并获取数据,仅供参考学习,如果需要下载网易云音乐,不如直接在客户端下载,客户端还可以下载无损音乐。
代码还是半成品,打算再做个音乐播放器,直接打包成exe,等有时间做好了再传到github上去,现在先把解析过程记录下来发布。
至于音乐搜索器,我所知道的有一个,地址:https://iw233.cn/music/
上面这个网页直接返回所有的搜索结果和音乐信息,如要使用,请自行解析(很简单的一个页面)。
网上流传的网易云音乐外链地址:http://music.163.com/song/media/outer/url?id=534544522.mp3,我也不知道怎么来的,输入音乐id即可获得下载链接,本着学习的态度,我认为还是从头到尾解析下载链接才好,因此不考虑使用该外链。
接口文档已发布
链接: https://25ukpfkme3.apifox.cn 访问密码: qtlXaZPH
二、解析过程
1、音乐搜索
(1)获取链接
来到网易云音乐首页,输入音乐名称,得到搜索结果
按F12,打开开发者工具,重新刷新一下界面,点击网络,在筛选器里只筛选XHR和Fetch数据,点击预览,一个一个链接往下找,直到找到我们需要的数据为止。
得到音乐搜索的api接口:https://music.163.com/weapi/cloudsearch/get/web?csrf_token=
csrf_token只有你登录时才有,有没有这个值不影响返回的结果。
需要注意,这个api接口的POST请求,后面所有的api接口都是POST请求。
(2)分析参数
点击负载,查看我们需要传入哪些数据
可以看到我们需要传入params和encSecKey两个参数,才能获取数据,否则得到的数据为空。
那么如何获取这两个参数呢?点击发起程序,随便点击一个,进入js脚本界面
点下面的{},将js代码格式化,这样我们更好查看代码
在js页面里按ctrl+f,直接搜索encSecKey,总共有三个结果,
可以看到,在执行window.asrsea()函数后,生成了params和encSecKey,
这里我们贴一下js源码,后面还会用到
var bMr5w = window.asrsea(JSON.stringify(i8a), bsg1x(["流泪", "强"]), bsg1x(TH5M.md), bsg1x(["爱心", "女孩", "惊恐", "大笑"]));
e8e.data = j8b.cr9i({
params: bMr5w.encText,
encSecKey: bMr5w.encSecKey
})
那么window.asrsea()是什么呢,搜索asrsea,可以看到window.asrsea()=d
找到d函数,就在window.asrsea()上面,
把js代码复制出来
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
}
其共涉及到三个函数a,b,c。我们先不急研究这三个函数的作用,先查看d函数传进去的四个参数d,e,f,g是什么。
其实从前面的window.asrsea()函数里我们就知道,这四个参数分别为JSON.stringify(i8a), bsg1x(["流泪", "强"]), bsg1x(TH5M.md), bsg1x(["爱心", "女孩", "惊恐", "大笑"]),
在这行打一个断点,重新刷新一下界面,进入调试模式。
在控制台依次输入这四个参数,获得其值
点击执行,继续执行下一步,再次查看四个参数的值,可以在监视里面输入四个参数,每次执行后会显示参数的值
经过多次调试后我们发现,除了第一个参数有变化之外,后面三个参数都是固定的,window.asrsea()函数会将这四个参数传入到d函数中,也就是d,e,f,g
e = '010001'
f = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'
g = '0CoJUm6Qyw8W8jud'
那么d参数是什么呢?在d函数里打个断点,调试页面直至进入我们的api接口https://music.163.com/weapi/cloudsearch/get/web?csrf_token=
为止
Y8Q = Y8Q.replace("api", "weapi");
仔细查看此段代码,这段代码是将链接里的api替换成weapi,因此可以根据Y8Q来定位到当前的链接地址,然后进行下一步调试。
在该行打一个断点,开始调试。
这里有个调试的小技巧,我们可以先在Y8Q那一行打一个断点,先进行调试执行,当Y8Q变为搜索的api接口后,再在window.asrsea()那里打一个断点,然后在d函数打一个断点,进行调试。
记得在Y8Q那里调试时先刷新一下页面,但是后面调试不要
这里我们定位到了api接口,注意api还没有换成weapi,点击执行下一步后,api被替换了
然后在window.asrsea打一个断点,点击执行
然后在d函数打一个断点,点击执行,得到d的值
直接将d复制过来,注意字符串前要加个r,要不然字符串里的''会被当做转义字符处理。
d = r'{"hlpretag":"<span class=\"s-fc7\">","hlposttag":"</span>","s":"自由の翅","type":"1","offset":"0","total":"true","limit":"30","csrf_token":""}'
e = '010001'
f = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876