鱼C论坛

 找回密码
 立即注册
查看: 1739|回复: 0

[技术交流] 【爬虫】网易云热评

[复制链接]
发表于 2021-9-1 15:37:08 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 大马强 于 2021-9-1 15:36 编辑


爬取网易云的评论,关键是获得两个加密参数 params, enSeckey

一、事前准备
以这首歌THE ANSWER为例,打开Chrome浏览器的调试工具, 点击newwork,重新刷新一下看看浏览器请求回来的数据包,找有评论信息的数据包,点击Initiator js脚本调用栈,点击最上方的也是最后一次执行的js脚本

                               
登录/注册后可看大图


二、找到未加密的数据
进入之后发现当前的内容是“不堪入目”的,先点击左下角的 “{}” ,让其阅读性好一点,然后将当前位置设置一个断点,浏览器不单单只请求评论的数据包,所以我们要观察旁边的Scope栏中变量,一步一步放掉不需要的请求,直到当浏览器请求https://music.163.com/weapi/comm ... nts/get?csrf_token=

                               
登录/注册后可看大图

然后再通过js栈中调用的js来寻找到未加密前的数据第一次出现的js,那么它的下一次js就是将参数加密,之后再重新设置一个断点,一步步调试找到该js加密参数的具体地方

                               
登录/注册后可看大图

目标锁定 window.asrsea函数, ctrl + F 寻找该函数具体实现的地方,找到了d函数,加密的过程就是再d函数里实现的了

                               
登录/注册后可看大图

三、找到加密原理
观察d函数可以发现,d函数有四个参数,与window.asrsea 函数的四个参数一一对应,利用浏览器的调试工具就可以得到参数的值。d函数中调用了两次b函数,一次a函数和一次c函数,再进一步观察其他函数,发现a函数作用时返回一个16为随机数给i变量,b函数是加密的params参数,c函数是加密的encSecKey参数
b,c函数分别用到了AES加密和RSA加密,前者AES加密的第一次加密是将d作为明文,g作为密钥,第二次加密是将第一次加密的密文再进行加密,i作为第二次加密的密钥,最终的带加密的params。后者用到三个参数 i,e,f,三个值都是定值,所以参数encSecKey可以固定下来
  1. function a(a) {a =16
  2.     var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";
  3.     for (d = 0; a > d; d += 1)  循环16次,创建一个16位随机字符串
  4.         e = Math.random() * b.length,
  5.         e = Math.floor(e),
  6.         c += b.charAt(e);
  7.     return c
  8. }
  9. function b(a, b) { a = 数据, g:定值, 经过AES加密 原文,密钥,偏移量,模式
  10.     var c = CryptoJS.enc.Utf8.parse(b) b
  11.         , d = CryptoJS.enc.Utf8.parse("0102030405060708")
  12.         , e = CryptoJS.enc.Utf8.parse(a)
  13.         , f = CryptoJS.AES.encrypt(e, c, { e 原文, c :密钥
  14.         iv: d, 偏移量
  15.         mode: CryptoJS.mode.CBC 模式
  16.     });
  17.     return f.toString()
  18. }
  19. function c(a, b, c) {
  20.     var d, e;
  21.     return setMaxDigits(131),
  22.     d = new RSAKeyPair(b,"",c),   <-密钥
  23.     e = encryptedString(d, a)  <-公钥加密 d:公钥 ,a
  24. }
  25. function d(d, e, f, g) {  d: 数据data, e:"010001", f:一个很长的字符串, g:"0CoJUm6Qyw8W8jud"
  26.     var h = {}
  27.         , i = a(16); -生成随机数
  28.     return h.encText = b(d, g),d=数据, g密钥
  29.     h.encText = b(h.encText, i), param :
  30.     encText两层加密

  31.     -- 可以将i定死,encSecKey就是一个定值
  32.     h.encSecKey = c(i, e, f), i :16位随机值,e定值,f定值  encSecKey
  33.     h
  34. }
复制代码

四、实现代码
  1. from Crypto.Cipher import AES
  2. from base64 import b64encode
  3. import requests
  4. import json
  5. import random
  6. url = "https://music.163.com/weapi/comment/resource/comments/get?csrf_token="
  7. data = {
  8.     "cursor": "-1",
  9.     "offset": "0",
  10.     "orderType": "1",
  11.     "pageNo": "1",
  12.     "pageSize": "20",
  13.     "rid": "R_SO_4_1855995767",
  14.     "threadId": "R_SO_4_1855995767"
  15. }

  16. # 函数d四个参数


  17. def get_i():
  18.     seq = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
  19.     str1 = ""
  20.     for i in range(16):
  21.         str1 += random.choice(seq)
  22.     print(str1)
  23.     return str1


  24. e = "010001"
  25. d = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
  26. g = "0CoJUm6Qyw8W8jud"
  27. i = "p6xB1rx37AU8O0KO"


  28. def get_encSeckey():
  29.     return "b742226290709f51abf9ad9a4e9136bd89036078368545a3f9a5ab938068d7a7be4d3f3fc2ea184090def069b85f75e4b443a43b1a872710c22ce983a3785fc074e799bd90d3e22a7a14d8a4864d647a72dc3a0de05a10ac61ef8114b631bf0079708ff79e0c2901ce0db1c26be78503550f65be6490ad08125ebf9744cc41cf"


  30. # 补位
  31. def to_16(data):
  32.     pd = 16 - len(data) % 16
  33.     data += chr(pd) * pd
  34.     return data


  35. def get_param(data):  # 字典1是加密不了的,需要处理成字符串
  36.     # param 是经过两次加密的
  37.     first = enc_param(data, g)
  38.     second = enc_param(first, i)
  39.     return second


  40. def enc_param(data, key):
  41.     iv = "0102030405060708"
  42.     # 创建一个AES加密器, 设置密钥,偏移量以及模式,前两者要为字符串格式
  43.     # AEs加密的数据格式一定是16的倍数,不到就用chr(x)补齐 格式为 "123456788chr(7)chr(7)"
  44.     data = to_16(data)
  45.     aes = AES.new(key=key.encode("utf-8"),
  46.                   iv=iv.encode("utf-8"), mode=AES.MODE_CBC)
  47.     # 加密后返回结果为字节,但需要的是字符串,并且该返回不能被 utf-8 格式所识别,还需要借助其他的库将其转换
  48.     bs = aes.encrypt(data.encode("utf-8"))
  49.     return str(b64encode(bs), "utf-8")


  50. # 将字典转换成字符串 ,需要json
  51. req = requests.post(url, data={
  52.     "params": get_param(json.dumps(data)),
  53.     "encSecKey": get_encSeckey()
  54. })
  55. res = req.json()["data"]["hotComments"]
  56. for content in res:
  57.     print(content["content"])
复制代码

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-30 18:05

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表