Osheep

时光不回头,当下最重要。

网易云音乐Web端的接口分析

网易云音乐Web端的接口分析

个人博客同步更新,阅读体验也会更好一点,欢迎访问

先看看云村有哪些榜单:

《网易云音乐Web端的接口分析》

飙升榜的访问地址:

http://music.163.com/#/discover/toplist?id=19723756

各个榜单地址就是最后的 id 不一样。但是这里的有一个坑,相当之坑,我不说,你先好好看链接就能发现了。

好的,我查看一下源代码

《网易云音乐Web端的接口分析》

这样没有问题吧,有问题,错,要看框架源代码。。。不清楚网易咋搞的,但是如果你在源代码里找你想要的,你会啥都找不到。喜欢用快捷键的,直接就在这里跪了。

好的,在 框架里找到列表,是个table,先别忙着解析,在找找,你会发现有 json 数据

《网易云音乐Web端的接口分析》

就是列表的,直接就拿了。解析网页的工具那么多,我还是喜欢美丽汤。

soup = BeautifulSoup(response.text, 'lxml')
json_data = json.loads(soup.find('textarea').text)

拿到json 数据,就有子页面了,id 就是单曲的id 了,从json 里拿

https://music.163.com/#/song?id=472361096

好像没啥好说的,唯一要说的地方就是,要注意链接里面的# 号,如果不是什么框架的限制,那只能说是心机啊。用代码访问链接的时候一定要把#号去掉,否则返回的一直是云村的首页,根本拿不到数据。不管你用什么 webkit, Js 渲染啦,延时等待啦都不行。请注意!请注意!请注意!

发现这个坑之后就可以到单曲页看看了。

比如我们想要拿热门评论,但是很快又会发现又找不到想要的数据了,去掉 # 号也不行,没错这次是真的 Js 渲染了页面了。到这里两条路,第一条,selenium 渲染页面,再得到page_source;第二条,分析接口,模拟请求数据。

相对来说,用 selenium 会简单一些,但是抓取效率慢一点。这是一个保险的方案。所以我们先试试第二条路。

抓包,我们发现这么一个接口:

《网易云音乐Web端的接口分析》

参数详情

《网易云音乐Web端的接口分析》

获取评论的接口

获取评论

https://music.163.com/weapi/v1/resource/comments/R_SO_4_472361096?csrf_token=

params=。。。。

encSecKey=。。。。。。太长了不写了

  1. post 请求
  2. 472361096 是单曲的id
  3. 请求的param,csrf_token,因为我没有登陆,所以没有值,但是也可以请求到
  4. 剩下就是请求体,params 和 encSecKey,你可以看一下截图,这两个是最难搞的,写些什么鬼也不知道,程序员就是这么互相为难的了。
  5. 返回的是评论列表 json

好的,我们先从服务端的响应中看一下有没有这两个鬼,我看了,没有。你可以自己看一下,万一你找到了,就可以跳过了。

响应里面没有,那就是生成的,js生成的,我们找一下js。有很多乱七八糟的js,最后我在core.js里面找到这么一句:

《网易云音乐Web端的接口分析》

好的,对上号了,基本就确定是生成的了。什么?怎么找的?搜索关键字啊,两万多行经过混淆的代码,难道一行一行读啊!

可以看到,我们要的两个鬼,params 和 encSecKey 都是来自 byw6q这个对象,我不知道叫不叫对象啊,我 js 学的浅,如果说错了,欢迎指正啊。

重点就是拿到 byw6q,可以看到 byw6q来自 window.asrsea ,看函数名就知道又是那些加密算法。。。。头疼。

我们搜索 asrsea,看到:

《网易云音乐Web端的接口分析》

ok,看一下 d是啥:

《网易云音乐Web端的接口分析》

好的,不能再截图了,太麻烦了。

我们看到 函数 d 有 4 个参数,那就对上号了。最后返回 h, h 就是我们前面说的 byw6q 的对象,里面有我们要的 params 和 encSecKey 。

可以看到,函数d里面有 函数a函数b函数c……为什么有省略号呢,因为 a,b,c 里面有其他的各种函数、变量,大概有这么多。

《网易云音乐Web端的接口分析》

额,怎么搞,证明你的时候到了,如果你又懂js,又懂python,这是最好的表现机会,把js的逻辑用python来写一遍,然后执行python里面的 函数d,得到 params 和 encSecKey ,继续愉快的爬虫。具体怎么搞呢,比如说我们先看js的 函数a

《网易云音乐Web端的接口分析》

我们可以把他翻译成pyhton:

def a(a):
    b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    c = ""
    for d in range(0, a):
        e = random.random() * len(b)
        e = math.floor(e)
        c += b[int(e)]
    return c

ok 原汁原味的翻译是这样的,可以优化一下:

def a(a):
    b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    c = ""
    for d in range(0, a):
        e = random.randint(0,len(b))
        c += b[e]
    return c

那执行 js 里面的 函数a ,和执行python 里面的 函数a 结果是不是一样的,这里当然不是一样啊,没看到里面有个 random 吗?但是,效果是一样的。

因为函数 a 的作用,就是生成一个长度为参数a,的随机字符串,看上面 函数d 的截图,参数a是16,就是长度为16的随机字符串。所以这里只要是16位,所有字符都在 变量b 里的字符串就行了。甚至可以不随机。

所以,先看懂,再写,会节省很多的时间,一五一十的翻译,那就逗逼了。

上面讲了大神的做法,我的水平也就翻译一下函数a玩玩,剩下的 函数b函数c是直接看不懂,只知道是在进行字符串的编码解码,加密解密,在函数c还用到了 RSA 算法,有兴趣的可以深入的了解一下,这些东西才是真正的一劳永逸的,搞懂之后,基本它只要撅屁股你就知道了。

讲讲我的做法:

  1. 最终我要的是函数d的返回值
  2. 那我就试一下直接跑js里面的函数d来得到,方法有很多
  3. 函数d一共有四个参数,所以我要做的就是获取这些参数,交给函数d

ok,我们就开始获取函数d的四个参数,使用 Fiddler 的自动响应功能,我们提前准备好一份本地的core.js,当请求 core.js时,给他替换成本地的core.js,而本地的js跟服务端的js基本是一样的,唯一不同是,我们自己的js ,在执行函数d的时候会将参数打印出来。

拷贝一份core.js,修改函数d:

《网易云音乐Web端的接口分析》

就是添加上通过控制台打印参数,在 Fiddler 里面设置自动响应规则:

《网易云音乐Web端的接口分析》

可以看到我设置了两个,为什么呢,因为如果不设置 pt_song_index.js 的话,控制台会报错,也加载不出来评论,管他呢,那就连他一起,做一份本地的。

设置好了之后,我们就到单曲页去刷新,换个单曲再试一下,得到这样的结果:

《网易云音乐Web端的接口分析》

看到没,p1,p2,p3,p4分别就是我们要的参数啊,经过多次的实验,可以得出

  1. p2,p3,p4是不变的
  2. p1 是个json 字符串
  3. 它调用了多次,只有p1参数在变,但是,只有p1 参数中有 id 才会是我们要的,因为它要标识啊

小功告成,暂时确定 四个参数如下,其中 p1 还有另外一种形式,那个应该是和翻页有关,这里就不管了,给各个参数的值:

p1={“id”:”484730186″,”lv”:-1,”tv”:-1,”csrf_token”:””}

p2=010001

p3=00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7

p4=0CoJUm6Qyw8W8jud

p1的id是当前单曲的id。

有了参数,我们就可以调用函数d了,方法很多,你可以新建一个js 文件,把函数d拷进去,因为用到函数a函数b函数c,所以这些也得拷进去,以此类推用到的都扔进去。也得几百行代码:

《网易云音乐Web端的接口分析》

执行d,这里用我用的是 execjs,也可以用 pyv8,等等很多方式,

h = execjs.compile(js_code).call('d', '{"id":%s,"lv":-1,"tv":-1,"csrf_token":""}' % song_id,
                                 settings.NETEASE_P2, 
                                 settings.NETEASE_P3, 
                                 settings.NETEASE_P4)

说明一下吧,反正废话都说了这么多了,函数名:d,后面是对应的p1,p2,p3,p4,四个参数,最后得到 h ,里面就有我们要的那两个什么鬼,params 和 encSecKey。

得到params 和 encSecKey 之后,我们就用 Postman 模拟一下:

《网易云音乐Web端的接口分析》

ok,这样就得到数据了。知道这获取那两个什么之后,一切都变得很简单了哦。

这里稍微注意一下模拟header,得有下面这两个才行:

《网易云音乐Web端的接口分析》

本到这里就差不多,剩下的只是实践。爬虫代码我就不给出了,但是我给一些截图吧,真想学的话,你不会介意打一遍的,而且。。。

解析榜单或者歌单的方法:

《网易云音乐Web端的接口分析》

那个 core1.js 我是想给一下的,因为那个容易出错,但是有700行代码,搞个网盘吧

链接:http://pan.baidu.com/s/1i53hhWT 密码:9g7n

获取歌词的接口

获取单曲的歌词

http://music.163.com/weapi/song/lyric?csrf_token=

这个我就不详细讲了,除了接口地址不同,好像其他都一样。

返回,有点多,上一下图

《网易云音乐Web端的接口分析》

具体的歌词

《网易云音乐Web端的接口分析》

好累啊,欢迎打赏。

点赞