爬虫--抓取网易云评论信息

本次爬取《若月亮没来live》这首歌的评论信息,网页源代码和F12的代码并不一样,所以我们尝试在XHR中找到评论信息。

评论信息的文件是get,在get文件里面找到url,可以看到url后面有个“csrf_token=”,这个是我们没有登录,如果登录的话“=”后面就会有东西。请求方式是post。

1.找到encSecKey和params的加密过程

网页往服务器发送的参数params是加密了的。服务器收到请求以后会根据encSecKey将params里的参数还原出来,然后再去做其他操作。

请求到get的时候initiator里面是执行哪些js脚本的过程,Request call stack下面的脚本是从下往上执行,最上面的是最后执行的脚本。

点开最上面的js脚本以后,找到发送数据的那一行代码,然后打上断点找commen的url

程序在这个函数里面被加密了。然后在这个函数里面打个断点,看是在哪里进行加密的。

此时的data还没有问题。

然后点击这个键。

就会进入到该界面,可以发现加密的数据是在这几行中进行的。

所以加密过程就是该行代码进行加密的。通过window.asrsea(参数, xxx, xxx, xxx)进行加密的

即params -> encText       encSecKey -> encSecKey

真实的参数就是下图这里:

网易音乐加密的网页源代码如下所示:

# 处理加密过程, 网易网页上的代码
"""
    function a(a = 16) {   # 返回随机的16位字符串
        var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";
        for (d = 0; a > d; d += 1)   # 循环16次
            e = Math.random() * b.length,  # 随机数
            e = Math.floor(e),  # 取整
            c += b.charAt(e);   # 取字符串中的xxx位置
        return c
    }
    function b(a, b) {  # a是要加密的内容
        var c = CryptoJS.enc.Utf8.parse(b)      # b是秘钥
          , d = CryptoJS.enc.Utf8.parse("0102030405060708")
          , e = CryptoJS.enc.Utf8.parse(a)      # e是数据
          , f = CryptoJS.AES.encrypt(e, c, {    # c:加密的秘钥
            iv: d,                      # 搜一下AES加密算法可知该变量是偏移量
            mode: CryptoJS.mode.CBC     # 模式:CBC
        });
        return f.toString()
    }
    function c(a, b, c) {  # c里面不产生随机数
        var d, e;
        return setMaxDigits(131),
        d = new RSAKeyPair(b,"",c),
        e = encryptedString(d, a)
    }
    function d(d, e, f, g) {  d:数据(data )  e:010001  f:很长  g:0CoJUm6Qyw8W8jud
        var h = {}    # 空对象
          , i = a(16);   # 进入到a函数中  参数为16
        h.encText = b(d, g),    # g是秘钥                              # params的第一次加密
        h.encText = b(h.encText, i),   # 返回的就是params    i也是秘钥   # params的第二次加密
        h.encSecKey = c(i, e, f),  # 返回的就是encSecKey,e和f是定死的,把i固定以后,得到的encSecKey也是固定的
        return h
    }
    
    encText两次加密:
    数据+g => b => 第一次加密的结果+i => b = params
"""

2.将encSecKey写死

通过搜索“window.asrsea”搜索加密过程,加密过程就是下图圈起来的那一坨代码。  “  window.asrsea = d”,故该加密过程入口是d函数

d函数的第一个参数d就是刚才拿到的数据,保存到data变量中

data = {
    "csrf_token": "",
    "cursor": "-1",
    "offset": "0",
    "orderType": "1",
    "pageNo": "1",
    "pageSize": "20",
    "rid": "R_SO_4_2158973221",
    "threadId": "R_SO_4_2158973221",
}

第二个参数e就是复制第二个参数打开console,往里面一运行就发现参数是'010001',第三个和第四个参数同第二个参数。

第三个参数是 f : "'00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'"

第四个参数是 g:'0CoJUm6Qyw8W8jud'

打个断点找到i的值写死,就可以使encSecKey固定不变。i: "jytyq7y8SwRmHgD7"

现在的encSecKey是

encSecKey: "7b043865d78705e97b83d04eecc0990ce8cfd4c1e61fc7196a7c7da7b020ed283c0bc163952fe2a35a821b8087819f768d3fbc240f6f424c118aa6a2caaae85e7d28faae0b8db1d7a121ff90cb71abad26d5f0646f63c8643e72ffde3fa065e9e7ef6c1970697e90fb4b051201ce86a5907dbde5e682524836e94068cecdff2a"

此时encSecKey是i为"jytyq7y8SwRmHgD7"的时候的值,

3.将params写死

# 将加密的结果处理成16的倍数, 为下面的加密算法服务
def to_16(data):
    pad = 16 - len(data) % 16
    data += chr(pad) * pad
    return data

# 加密过程(算法)
def enc_params(data, key):
    iv = "0102030405060708"     # 下面b函数中给了iv=d  而d="0102030405060708"
    data = to_16(data)
    # key: 秘钥   IV: 偏移量   mode: 模式
    aes = AES.new(key=key.encode("utf-8"), IV=iv.encode("utf-8"), mode=AES.MODE_CBC)   # new一个能进行AES加密的工具
    bs = aes.encrypt(data.encode("utf-8"))   # 加密, 加密的内容的长度必须是16的倍数  需将data转换为字节
    # 加密的结果不能直接被decode("utf-8")识别,所以不能直接decode,需要导入b64decode
    return str(b64encode(bs), "utf-8")     # 结果转化成字符串返回

4.发送请求,得到歌曲评论数据

整个源代码如下所示:

        爬取网易相关的信息都是这个流程,例如网易新闻、网易云音乐等。

# 1.找到未加密的参数                                            # window.asrsea(参数, xxx, xxx, xxx)
# 2.想办法把参数进行加密(params,encSecKey),必须参考网易加密的逻辑   # params -> encText  encSecKey -> encSecKey
# 3.请求到网易,拿到评论信息

# AES加密,需要安装pycrypto: pip install pycrypto
# 安装时电脑上需要有vs
# 安装时候会可能会出现一些错误,可以网上寻找解决办法
from Crypto.Cipher import AES
from base64 import b64encode    # 加密结果进行字节
import requests
import json

url = "https://music.163.com/weapi/comment/resource/comments/get?csrf_token="

# 请求方式是post,以下是真实的参数
# window.asrsea(参数, xxx, xxx, xxx)函数的四个参数d,e,f,g
data = {  # 现在是字典
    "csrf_token": "",
    "cursor": "-1",
    "offset": "0",
    "orderType": "1",
    "pageNo": "1",
    "pageSize": "20",
    "rid": "R_SO_4_2158973221",
    "threadId": "R_SO_4_2158973221",
}
# 服务于d的
e = "010001"
f = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
g = "0CoJUm6Qyw8W8jud"
i = "jytyq7y8SwRmHgD7"  # 手动固定的  ->  网易音乐评论页面函数中是随机的

def get_encSecKey(): # 由于i被我们固定了,所以encSecText就是固定的,c()函数的结果就是固定的
    # 返回encSecKey
    return "7b043865d78705e97b83d04eecc0990ce8cfd4c1e61fc7196a7c7da7b020ed283c0bc163952fe2a35a821b8087819f768d3fbc240f6f424c118aa6a2caaae85e7d28faae0b8db1d7a121ff90cb71abad26d5f0646f63c8643e72ffde3fa065e9e7ef6c1970697e90fb4b051201ce86a5907dbde5e682524836e94068cecdff2a"

# 把参数params进行加密
# 需要将函数中参数data转换为字符串,所以需要json包
def get_params(data):               # 需要四个参数,e、f、g、i等都是固定的,故只需要将data这个变化的参数写死, 默认data是字符串
    first = enc_params(data, g)     # 第一次加密
    second = enc_params(first, i)
    return second                   # 加密的结果,返回的就是params

# 将加密的结果处理成16的倍数, 为下面的加密算法服务
def to_16(data):
    pad = 16 - len(data) % 16
    data += chr(pad) * pad
    return data

# 加密过程(算法)
def enc_params(data, key):
    iv = "0102030405060708"     # 下面b函数中给了iv=d  而d="0102030405060708"
    data = to_16(data)
    # key: 秘钥   IV: 偏移量   mode: 模式
    aes = AES.new(key=key.encode("utf-8"), IV=iv.encode("utf-8"), mode=AES.MODE_CBC)   # new一个能进行AES加密的工具
    bs = aes.encrypt(data.encode("utf-8"))   # 加密, 加密的内容的长度必须是16的倍数  需将data转换为字节
    # 加密的结果不能直接被decode("utf-8")识别,所以不能直接decode,需要导入b64decode
    return str(b64encode(bs), "utf-8")     # 结果转化成字符串返回






# 处理加密过程, 网易网页上的代码
"""
    function a(a = 16) {   # 返回随机的16位字符串
        var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";
        for (d = 0; a > d; d += 1)   # 循环16次
            e = Math.random() * b.length,  # 随机数
            e = Math.floor(e),  # 取整
            c += b.charAt(e);   # 取字符串中的xxx位置
        return c
    }
    function b(a, b) {  # a是要加密的内容
        var c = CryptoJS.enc.Utf8.parse(b)      # b是秘钥
          , d = CryptoJS.enc.Utf8.parse("0102030405060708")
          , e = CryptoJS.enc.Utf8.parse(a)      # e是数据
          , f = CryptoJS.AES.encrypt(e, c, {    # c:加密的秘钥
            iv: d,                      # 搜一下AES加密算法可知该变量是偏移量
            mode: CryptoJS.mode.CBC     # 模式:CBC
        });
        return f.toString()
    }
    function c(a, b, c) {  # c里面不产生随机数
        var d, e;
        return setMaxDigits(131),
        d = new RSAKeyPair(b,"",c),
        e = encryptedString(d, a)
    }
    function d(d, e, f, g) {  d:数据(data )  e:010001  f:很长  g:0CoJUm6Qyw8W8jud
        var h = {}    # 空对象
          , i = a(16);   # 进入到a函数中  参数为16
        h.encText = b(d, g),    # g是秘钥                              # params的第一次加密
        h.encText = b(h.encText, i),   # 返回的就是params    i也是秘钥   # params的第二次加密
        h.encSecKey = c(i, e, f),  # 返回的就是encSecKey,e和f是定死的,把i固定以后,得到的encSecKey也是固定的
        return h
    }
    
    encText两次加密:
    数据+g => b => 第一次加密的结果+i => b = params
"""

# 发送请求,得到歌曲评论结果
resp = requests.post(url, data={
    "params": get_params(json.dumps(data)),   # 需要将data转换为json的字符串形式然后作为参数进入该函数中
    "encSecKey": get_encSecKey()
})

print(resp.text)





  • 32
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值