网易云音乐Web端的接口分析
个人博客同步更新,阅读体验也会更好一点,欢迎访问
先看看云村有哪些榜单:
飙升榜的访问地址:
http://music.163.com/#/discover/toplist?id=19723756
各个榜单地址就是最后的 id 不一样。但是这里的有一个坑,相当之坑,我不说,你先好好看链接就能发现了。
好的,我查看一下源代码
这样没有问题吧,有问题,错,要看框架源代码。。。不清楚网易咋搞的,但是如果你在源代码里找你想要的,你会啥都找不到。喜欢用快捷键的,直接就在这里跪了。
好的,在 框架里找到列表,是个table,先别忙着解析,在找找,你会发现有 json 数据
就是列表的,直接就拿了。解析网页的工具那么多,我还是喜欢美丽汤。
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 会简单一些,但是抓取效率慢一点。这是一个保险的方案。所以我们先试试第二条路。
抓包,我们发现这么一个接口:
参数详情
获取评论的接口
获取评论
https://music.163.com/weapi/v1/resource/comments/R_SO_4_472361096?csrf_token=
params=。。。。
encSecKey=。。。。。。太长了不写了
- post 请求
- 472361096 是单曲的id
- 请求的param,csrf_token,因为我没有登陆,所以没有值,但是也可以请求到
- 剩下就是请求体,params 和 encSecKey,你可以看一下截图,这两个是最难搞的,写些什么鬼也不知道,程序员就是这么互相为难的了。
- 返回的是评论列表 json
好的,我们先从服务端的响应中看一下有没有这两个鬼,我看了,没有。你可以自己看一下,万一你找到了,就可以跳过了。
响应里面没有,那就是生成的,js生成的,我们找一下js。有很多乱七八糟的js,最后我在core.js里面找到这么一句:
好的,对上号了,基本就确定是生成的了。什么?怎么找的?搜索关键字啊,两万多行经过混淆的代码,难道一行一行读啊!
可以看到,我们要的两个鬼,params 和 encSecKey 都是来自 byw6q
这个对象,我不知道叫不叫对象啊,我 js 学的浅,如果说错了,欢迎指正啊。
重点就是拿到 byw6q
,可以看到 byw6q
来自 window.asrsea ,看函数名就知道又是那些加密算法。。。。头疼。
我们搜索 asrsea
,看到:
ok,看一下 d
是啥:
好的,不能再截图了,太麻烦了。
我们看到 函数 d
有 4 个参数,那就对上号了。最后返回 h, h 就是我们前面说的 byw6q
的对象,里面有我们要的 params 和 encSecKey 。
可以看到,函数d
里面有 函数a
,函数b
,函数c
......为什么有省略号呢,因为 a,b,c 里面有其他的各种函数、变量,大概有这么多。
额,怎么搞,证明你的时候到了,如果你又懂js,又懂python,这是最好的表现机会,把js的逻辑用python来写一遍,然后执行python里面的 函数d
,得到 params 和 encSecKey ,继续愉快的爬虫。具体怎么搞呢,比如说我们先看js的 函数a
:
我们可以把他翻译成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 算法,有兴趣的可以深入的了解一下,这些东西才是真正的一劳永逸的,搞懂之后,基本它只要撅屁股你就知道了。
讲讲我的做法:
- 最终我要的是
函数d
的返回值 - 那我就试一下直接跑js里面的
函数d
来得到,方法有很多 -
函数d
一共有四个参数,所以我要做的就是获取这些参数,交给函数d
ok,我们就开始获取函数d
的四个参数,使用 Fiddler 的自动响应功能,我们提前准备好一份本地的core.js,当请求 core.js时,给他替换成本地的core.js,而本地的js跟服务端的js基本是一样的,唯一不同是,我们自己的js ,在执行函数d
的时候会将参数打印出来。
拷贝一份core.js,修改函数d
:
就是添加上通过控制台打印参数,在 Fiddler 里面设置自动响应规则:
可以看到我设置了两个,为什么呢,因为如果不设置 pt_song_index.js 的话,控制台会报错,也加载不出来评论,管他呢,那就连他一起,做一份本地的。
设置好了之后,我们就到单曲页去刷新,换个单曲再试一下,得到这样的结果:
看到没,p1,p2,p3,p4分别就是我们要的参数啊,经过多次的实验,可以得出
- p2,p3,p4是不变的
- p1 是个json 字符串
- 它调用了多次,只有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
,所以这些也得拷进去,以此类推用到的都扔进去。也得几百行代码:
执行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 模拟一下:
ok,这样就得到数据了。知道这获取那两个什么之后,一切都变得很简单了哦。
这里稍微注意一下模拟header,得有下面这两个才行:
本到这里就差不多,剩下的只是实践。爬虫代码我就不给出了,但是我给一些截图吧,真想学的话,你不会介意打一遍的,而且。。。
解析榜单或者歌单的方法:
那个 core1.js 我是想给一下的,因为那个容易出错,但是有700行代码,搞个网盘吧
链接:http://pan.baidu.com/s/1i53hhWT 密码:9g7n
获取歌词的接口
获取单曲的歌词
http://music.163.com/weapi/song/lyric?csrf_token=
这个我就不详细讲了,除了接口地址不同,好像其他都一样。
返回,有点多,上一下图
具体的歌词
好累啊,欢迎打赏。