最近更新频率慢了,这不是因为CK3发售了嘛,一个字就是“肝”。今天来看一下网易云音乐两个加密参数paramsencSecKey,顺便抓取一波某歌单的粉丝,有入库哦,使用mysql存储,觉得有帮助的别忘了关注一下公众号啊,完整的JS代码都已整理好,请关注知识图谱与大数据公众号,找到本文点击文末阅读更多获取。我的文章一般都有完整代码,创作不易啊,大家请多关注啊,当然不关注想白票也无所谓。

目标

网易云音乐只需要解密paramsencSecKey就可以开始快乐的抓取了,当然你没有足够的代理IP的话,还是要慢点爬,废话不多说,直接开整。

请求

老规矩,先看看我们要抓的页面样子:



查看网络请求:



从名字上就可以快速定位是哪个请求,是POST请求,那看看它提交了哪些参数吧,FormData如下:



提交的参数即前面提过的paramsencSecKey,是加密过的,看看返回的内容的格式:



ok,基本的东西我们都已经知道,可以进入下一步了找到解密两个参数了。

分析

调试前我们得先找到这两个值的位置,那就搜索呗,先定位JS文件再定位代码位置。怎么搜索应该都知道的吧,搜paramsencSecKey均可,搜出来多个结果不确定是哪个文件的话可以每个点进去再搜索一下关键参数,以此确定是否是目标文件,这里我直接标记了正确文件,大家点击进去即可。



进入JS文件后,同样搜索关键参数paramsencSecKey



找到了encSecKey的位置,把这几行代码抠出来分析一下:

  1. var bVZ8R = window.asrsea(JSON.stringify(i0x), bqN0x(["流泪", "强"]), bqN0x(Wx5C.md), bqN0x(["爱心", "女孩", "惊恐", "大笑"]));
  2. e0x.data = j0x.cs1x({
  3. params: bVZ8R.encText,
  4. encSecKey: bVZ8R.encSecKey
  5. })

粗略看,paramsencSecKey来自bVZ8R.encTextbVZ8R.encSecKey,而bVZ8Rwindow.asrsea的结果,window.asrsea有四个参数,JSON.stringify(i0x), bqN0x(["流泪", "强"]), bqN0x(Wx5C.md), bqN0x(["爱心", "女孩", "惊恐", "大笑"],先看后面三个参数,从它们固定的值可以大胆推测这三个值也是固定的。之所以说都是固定的,看看Wx5C.md



Wx5C.md是一个固定好的数组,而bqN0x(["流泪", "强"])bqN0x(["爱心", "女孩", "惊恐", "大笑"]这结果肯定也是不会变的,如下图,测试了一下:



大概弄清楚了这几个参数,剩下的就是搞明白window.asrsea的具体实现方式,还有i0x是什么样的,进入调试环节。

调试

window.asrsea打上断点,我的代码位置是13133行,点击粉丝列表下一页就会激活断点,在激活断点的同时我们也能一睹i0x的芳容,在控制台中输入i0x

limit、offset、total、userId这些其实都是可知的,而csrf_token的产生可以看这里,细心的童靴应该早就发现了:

  1. }
  2. i0x["csrf_token"] = v0x.gP3x("__csrf"); ## csrf_token在这里产生
  3. X0x = X0x.replace("api", "weapi");
  4. e0x.method = "post";
  5. delete e0x.query;
  6. var bVZ8R = window.asrsea(JSON.stringify(i0x), bqN0x(["流泪", "强"]), bqN0x(Wx5C.md), bqN0x(["爱心", "女孩", "惊恐", "大笑"]));

我点进v0x.gP3x函数看了看:



从代码中可以看出csrf_token来自于Cookie中的__csrf:



那这个值就可以在请求网页的时候从cookie中获取到,继续调试window.asrsea吧。一路点击下一步,进入函数中。



跳到一个d(d,e,f,g)函数里,稍微往下一看,发现window.asrsea就等于这个d函数,哦了,那就调试这个d函数就行:

  1. function d(d, e, f, g) {
  2. var h = {}
  3. , i = a(16);
  4. return h.encText = b(d, g),
  5. h.encText = b(h.encText, i),
  6. h.encSecKey = c(i, e, f),
  7. h
  8. }

进入a函数:



大概看出来a函数是产生随机数的,继续运行,进入b函数:



熟悉的AES加密,继续运行进入c函数:



又是熟悉的RSA加密,网易可真谨慎,各种加密。到这里总的框架已经调试完了,剩下的无非就是抠JS代码了。

python运行

这次不是单单运行了结果哦,还带上了爬取与入库:

获取paramsencSecKey

  1. def get_enc(self,a):
  2. with open('..//js//wangyiyun.js', encoding='utf-8') as f:
  3. wangyiyun = f.read()
  4. js = execjs.compile(wangyiyun)
  5. logid = js.call('get_pwd', a)
  6. print(logid)
  7. return logid

抓取

  1. def get_fans(self):
  2. resp = self.get_home_page()
  3. print(resp.cookies)
  4. print(resp.status_code)
  5. time.sleep(6)
  6. limit = 20
  7. for i in range(1,110):
  8. print("第{}页".format(i+1))
  9. offset = limit*i
  10. a = {"userId": "46991111", "offset": str(offset), "total": "false", "limit": str(limit), "csrf_token": ""}
  11. print(a)
  12. logid = self.get_enc(a)
  13. data = {
  14. "params":logid["encText"],
  15. "encSecKey":logid["encSecKey"],
  16. }
  17. print(data)
  18. fans_url = "https://music.163.com/weapi/user/getfolloweds?csrf_token="
  19. resp = self.session.post(url=fans_url,data=data,headers=self.headers)
  20. followed = json.loads(resp.text)
  21. followed_list = []
  22. for foll in followed["followeds"]:
  23. foll_dict = {}
  24. foll_dict["short_name"] = foll.get("py","") #缩写
  25. foll_dict["userId"] = foll.get("userId","") #用户ID
  26. foll_dict["nickname"] = foll.get("nickname","") #昵称
  27. foll_dict["vipType"] = foll.get("vipType","") # vip
  28. foll_dict["eventCount"] = foll.get("eventCount","")#动态
  29. foll_dict["vipRights"] = str(foll.get("vipRights","")) #VIP权益
  30. foll_dict["gender"] = foll.get("gender","") #性别
  31. foll_dict["avatarUrl"] = foll.get("avatarUrl","") #头像
  32. foll_dict["followed"] = foll.get("followed","")
  33. foll_dict["followeds"] = foll.get("followeds","") #粉丝
  34. foll_dict["follows"] = foll.get("follows","") #关注
  35. foll_dict["playlistCount"] = foll.get("playlistCount","") #歌单
  36. foll_dict["mutual"] = foll.get("mutual","") #
  37. foll_dict["expertTags"] = str(foll.get("expertTags",""))
  38. foll_dict["experts"] = str(foll.get("experts",""))
  39. print(foll_dict)
  40. followed_list.append(foll_dict)
  41. self.mysql.insert("music",followed_list)
  42. tm = random.randint(1030)
  43. time.sleep(tm)

这里要注意一下,要抓取指定的页面你还得先访问这个页面,不能直接请求"https://music.163.com/weapi/user/getfolloweds?csrf_token=这个链接,因为它根本就没有带关于哪个页面的信息。

请求指定网页

  1. def get_home_page(self):
  2. url = "https://music.163.com/#/user/home?id=1737833656"
  3. resp = self.session.get(url)
  4. return resp

表结构

  1. @property
  2. def create_table_sql(self):
  3. create_table = """
  4. CREATE TABLE IF NOT EXISTS music (
  5. short_name varchar(30) ,
  6. userId varchar(100) NOT NULL,
  7. nickname varchar(30),
  8. vipType varchar(30) ,
  9. eventCount varchar(200),
  10. vipRights varchar(900),
  11. gender varchar(900),
  12. avatarUrl varchar(200),
  13. followed varchar(30),
  14. followeds varchar(30),
  15. follows varchar(30),
  16. playlistCount varchar(30),
  17. mutual varchar(30),
  18. expertTags varchar(30),
  19. experts varchar(30),
  20. PRIMARY KEY (userId)
  21. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"""
  22. return create_table

入库

  1. def insert(self,table,data_list):
  2. if len(data_list) > 0:
  3. data_list = [{k: v
  4. for k, v in data.items() if v is not None}
  5. for data in data_list]
  6. keys = ", ".join(data_list[0].keys())
  7. values = ", ".join(["%s"] * len(data_list[0]))
  8. sql = """INSERT INTO {table}({keys}) VALUES ({values}) ON
  9. DUPLICATE KEY UPDATE""".format(table=table,
  10. keys=keys,
  11. values=values)
  12. update = ",".join([
  13. " {key} = values({key})".format(key=key)
  14. for key in data_list[0]
  15. ])
  16. sql += update
  17. print(sql)
  18. self.connect()
  19. try:
  20. ret = self.cursor.executemany(sql, [tuple(data.values()) for data in data_list])
  21. self.conn.commit()
  22. except Exception as e:
  23. self.conn.rollback()
  24. print("Error: ", e)
  25. traceback.print_exc()
  26. finally:
  27. self.close()

过程

结束

快乐的时光过得真快,到这里就结束了,抓取过程与入库大家可以作为一个参考。完整的JS代码都已整理好,请关注知识图谱与大数据公众号,找到本文点击文末阅读更多获取,创作不易,请多关注,当然不关注也无所谓。

这个网易云JS解密,老网抑云看了都直呼内行的更多相关文章

  1. Web前端:博客美化:四、网易云音乐单曲播放器

    1.页面定制CSS代码 /*3.音乐播放器*/ .content-wrap { overflow-y: scroll; -webkit-overflow-scrolling: touch; } /* ...

  2. 来自网易云的黑科技,带尖角的div......

    今天在网易云的网页版听歌,话说Steve Vai的曲子永远是这么让人揣摩不透,不过我还时更喜欢老Joe,咦,跑题了··· 大家可以看到评论输入框和回复框,上面都有个小尖角,实现的方式有很多,我一般是用 ...

  3. 爬虫实战(二) 用Python爬取网易云歌单

    最近,博主喜欢上了听歌,但是又苦于找不到好音乐,于是就打算到网易云的歌单中逛逛 本着 "用技术改变生活" 的想法,于是便想着写一个爬虫爬取网易云的歌单,并按播放量自动进行排序 这篇 ...

  4. 用其他音乐源帮帮网易云,Ubuntu听歌利器

    镜像文章 1.用其他音乐源帮帮网易云,Android听歌利器 2.用其他音乐源帮帮网易云,Windows听歌利器 众所周知,国内只有网易云推出了Linux的客户端,在Listen 1并不十分好用的基础 ...

  5. ubuntu16.04 安装网易云音乐

    最爱的播放器 网易云音乐 哈哈,刚刚折腾了双系统,立马开始了软件安装. 网易云音乐从官网下载对应的 64 位版本,我下载的是 netease-cloud-music_1.0.0_amd64_ubunt ...

  6. 解决Windows x86网易云音乐不能将音乐下载到SD卡的BUG

    由于我个人最常用的电脑是Surface pro4 256G版本,装了不少生产力空间还挺吃紧的,音乐之类的必然都存单独的SD卡里.用UWP版本的网易云音乐倒是没问题,最近问题来了,UWP版本的网易云音乐 ...

  7. KEUC首次落地中国,网易云深度剖析Kubernetes优化与实践

    本文由  网易云发布. 10 月 15 日,聚焦 Kubernetes 中国行业应用与技术落地的首届中国 Kubernetes 用户大会(KEUC)在杭州成功举办.本次大会吸引了来自全球各地的技术精英 ...

  8. 网易云基于 Kubernetes 的深度定制化实践

    本文由  网易云发布. 2017 年,Kubernetes 超越 Mesos 和 Docker Swarm成为最受欢迎的容器编排技术.网易云从 2015 下半年开始向 Kubernetes 社区贡献代 ...

  9. 网易云易盾与A10 Networks达成战略合作 携手打造抗DDoS攻击的解决方案

    欢迎访问网易云社区,了解更多网易技术产品运营经验. 2018年9月,网易云易盾宣布,与智能和自动化网络安全解决方案提供商A10 Networks结成战略合作伙伴关系.双方将在抗DDoS攻击领域展开深入 ...

随机推荐

  1. 面试【JAVA基础】其他

    1.自定义注解 @target 说明了Annotation所修饰的对象范围: constructor.method.field.package.type等等. @retention 定义了该Annot ...

  2. Angular(二) - 组件Component

    1. 组件Component示例 2. Component常用的几个选项 3. Component全部的选项 3.1 继承自@Directive装饰器的选项 3.2 @Component自己特有的选项 ...

  3. day48:django前戏之HTTP协议&自定义web框架

    目录 1.HTTP协议 1.HTTP协议简介 2.HTTP协议概述 3.HTTP协议工作原理 4.HTTP协议请求方法 5.HTTP协议状态码 6.URL 7.HTTP请求格式 8.HTTP响应格式 ...

  4. MyBatis的逆向工程、Example类

    public void testFindUserByName(){ //通过criteria构造查询条件 UserExample userExample = new UserExample(); us ...

  5. 局域网内笔记本分屏到android手机上

    前提 笔记本电脑1台 安卓/ios手机1部 局域网 spacedesk 预览 参考: https://www.appinn.com/spacedesk https://spacedesk.net/de ...

  6. 高可用服务之Keepalived利用脚本实现服务的可用性检测

    上一篇博客主要聊到了keepalived高可用LVS集群的相关配置,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/13659428.html:keepalive ...

  7. 归并排序求逆序对(poj 2299)

    归并排序求逆序对 题目大意 给你多个序列,让你求出每个序列中逆序对的数量. 输入:每组数据以一个数 n 开头,以下n行,每行一个数字,代表这个序列: 输出:对于输出对应该组数据的逆序对的数量: 顺便在 ...

  8. [06] 优化C#服务器的思路和工具的使用

    优化C#服务器的思路和工具的使用 优化服务器之前, 需要先对问题的规模做合理的预估, 然后对关键的数据做采样, 做对比, 看和自己的预估是否一致, 误差大在什么地方, 是预估的不对, 还是系统实现有问 ...

  9. Python 之 Django框架( Cookie和Session、Django中间件、AJAX、Django序列化)

    12.4 Cookie和Session 12.41 cookie Cookie具体指的是一段小信息,它是服务器发送出来存储在浏览器上的一组组键值对,下次访问服务器时浏览器会自动携带这些键值对,以便服务 ...

  10. maven-shade-plugin插件未生效原因分析

    今天在项目的pom文件中引入maven-shade-plugin插件,构建一个uber-jar(包含所有依赖的jar包),但是诡异的事情出现了,执行mvn package后生成的jar包竟然没有包含被 ...