网易云音乐评论爬虫(2):歌曲的全部评论

2018 年 10 月 11 日 Python开发者

(点击上方公众号,可快速关注)


来源:志颖(本文来自作者的投稿,简介见末尾)

www.zhouzying.cn/58.html


用过网易云音乐听歌的朋友都知道,网易云音乐每首歌曲后面都有很多评论,热门歌曲的评论更是接近百万或者是超过百万条.现在我就来分享一下如何爬取网易云音乐歌曲的全部评论,由于网易云音乐的评论都做了混淆加密处理,因此我们需要深入了解它的加密过程之后才能爬取到网易云音乐歌曲的全部评论.

一,首先分析数据的请求方式

网易云音乐歌曲页面的URL形式为https://music.163.com/#/song?id=歌曲id号,这里我用Delacey的Dream it possible 为例进行讲解,它的URL为https://music.163.com/#/song?id=38592976.接下来开始分析数据的请求方式.

由于网易云音乐的评论是通过Ajax传输,我们打开浏览器的开发者工具(检查元素),选中控制面板中的Network,再点击XHR(捕获ajax数据),然后点击左上角的重新加载,会看到下面图片中的数据请求列表

点击R_SO_4_38592976?csrf_token=cdee144903c5a32e6752f50180329fc9这一行,再点击Preview

发现我们所需要的数据就在这json格式的数据中,其中comments中是第一页的全部评论,一共20条,hotcomments是精彩评论一共有15条,每首歌曲只有第一页评论才有精彩评论.接着看一下它的请求头,点击Headers

我们发现的它是个post请求,向下滑你会发现这个post请求还带有数据

这些数据都是经过加密处理的,因此我们需要分析它的加密过程来生成相应的参数,然后把加密后的参数加到post请求中才能获取到我们需要的评论数据.

二,分析加密过程

通过断点调试发现params和encSecKey是由js脚本中的window.asrsea()函数生成的.

我们发现window.asrsea()函数有4个参数,在浏览器的js控制台分别对这四个参数进行调试:

后面三个参数是定值,只有第一个参数是控制评论页面偏移量的参数,它是一个变量.笔者经过分析发现第一个参数的形式是:

{"rid":"R_SO_4_38592976","offset":"0","total":"True","limit":"20","csrf_token":""}


下面我来详细讲解这个变量的发现过程:

首先找到core_dfe56728795d119e4d476fd09ea2dc51.js这个js脚本,然后将断点打在第12973行,点击第一页评论,页面加载到断点处便停止了

然后按下电脑的Esc键打开js控制台,输入i1x,查看第一个变量:

这是第一页的i1x的值,接下来看第二页的(需要点击第2页,然后输入i1x的值):

再看第3页:

再看第4页:

通过这几页的分析,我们可以得到i1x值的变化规律,且可以得到它的一般形式:

{"rid":"R_SO_4_38592976","offset":"0","total":"True","limit":"20","csrf_token":""}


offset和limit是必选参数,其他参数是可选的,其他参数不影响data数据的生成,offset (页面偏移量) = (页数-1) * 20, 注意limit最大值为100,当设为100时,获取第二页时,默认前一页是20个评论,也就是说第二页最新评论有80个,有20个是第一页显示的.因此我们可以构造第一个参数为:


# 偏移量,page是页数

offset = (page-1) * 20

msg = '{"offset":' + str(offset) + ',"total":"True","limit":"20","csrf_token":""}


接下来,我们来看一下window.asrsea()函数的整个加密过程:


!function() {

    // 函数a生成长度为16的随机字符串

    function a(a) {

        var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";

        for (d = 0; a > d; d += 1)

            e = Math.random() * b.length,

            e = Math.floor(e),

            c += b.charAt(e);

        return c

    }

    // 函数b实现AES加密

    function b(a, b) {

        var c = CryptoJS.enc.Utf8.parse(b)

          , d = CryptoJS.enc.Utf8.parse("0102030405060708")

          , e = CryptoJS.enc.Utf8.parse(a)

          , f = CryptoJS.AES.encrypt(e, c, {

            iv: d,

            mode: CryptoJS.mode.CBC

        });

        return f.toString()

    }

    // 函数c实现RSA加密

    function c(a, b, c) {

        var d, e;

        return setMaxDigits(131),

        d = new RSAKeyPair(b,"",c),

        e = encryptedString(d, a)

    }

    function d(d, e, f, g) {

        var h = {}

          , i = a(16);

        return h.encText = b(d, g),

        h.encText = b(h.encText, i),

        h.encSecKey = c(i, e, f),

        h

    }

    function e(a, b, d, e) {

        var f = {};

        return f.encText = c(a + e, b, d),

        f

    }

    window.asrsea = d,

    window.ecnonasr = e

}();


window.asrsea()函数就是上面的d函数,现在我们来看函数d:


function d(d, e, f, g) {

        var h = {}

          , i = a(16);

        return h.encText = b(d, g),   // 第一次AES加密

        h.encText = b(h.encText, i),    // 第二次AES加密

        h.encSecKey = c(i, e, f),    // RSA加密

        h

    }


参数h.encText是经过两次AES加密得到的,h.encSecKey是经过一次RSA加密得到的,其中i是随机生成的长度为16的随机字符串.

三,生成加密参数

首先我们需要生成长度为16的随机字符串,这里我们仿照上面的javascript的实现,用Python生成16位长的随机字符串:

# 生成随机字符串

def generate_random_strs(length):

    string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

    # 控制次数参数i

    i = 0

    # 初始化随机字符串

    random_strs  = ""

    while i < length:

        e = random.random() * len(string)

        # 向下取整

        e = math.floor(e)

        random_strs = random_strs + list(string)[e]

        i = i + 1

    return random_strs


接着用Python实现AES加密,这里要用到pycrypto库,先安装好这个库:


pip   install   pycrypto


然后导入加密模块:


from Crypto.Cipher import AES


由于AES加密的明文长度必须是16的倍数,因此我们需要对明文进行必要的填充,以满足它的长度是16的倍数:


# msg是需要加密的明文,如果不是16的倍数则进行填充(paddiing)

padding = 16 - len(msg) % 16

# 这里使用padding对应的单字符进行填充

msg = msg + padding * chr(padding)


AES加密的模式是AES.MODE_CBC,初始化向量iv=’0102030405060708′,具体的AES加密:


# AES加密

def AESencrypt(msg, key):

    # 如果不是16的倍数则进行填充(paddiing)

    padding = 16 - len(msg) % 16

    # 这里使用padding对应的单字符进行填充

    msg = msg + padding * chr(padding)

    # 用来加密或者解密的初始向量(必须是16位)

    iv = '0102030405060708'

    cipher = AES.new(key, AES.MODE_CBC, iv)

    # 加密后得到的是bytes类型的数据

    encryptedbytes = cipher.encrypt(msg)

    # 使用Base64进行编码,返回byte字符串

    encodestrs = base64.b64encode(encryptedbytes)

    # 对byte字符串按utf-8进行解码

    enctext = encodestrs.decode('utf-8')

    return enctext


然后是RSA加密.首先我简单介绍一下RSA的加密过程.在RSA中,明文,密钥和密文都是数字.RSA的加密过程可以用下列的公式来表达,这个公式非常的重要,你只有理解了这个公式,才能用Python实现RSA加密.

密文    =    明文E mod  N           (RSA加密)

RSA的密文是对代表明文的数字的E次方求mod N 的结果, 通俗的讲就是将明文和自己做E次乘法,然后将其结果除以N 求余数,这个余数就是密文.

下面来看具体的RSA加密代码实现:

# RSA加密

def RSAencrypt(randomstrs, key, f):

    # 随机字符串逆序排列

    string = randomstrs[::-1]

    # 将随机字符串转换成byte类型数据

    text = bytes(string, 'utf-8')

    seckey = int(codecs.encode(text, encoding='hex'), 16)**int(key, 16) % int(f, 16)

    return format(seckey, 'x').zfill(256)


RSA加密后得到的字符串长为256,这里不够长我们用x字符填充.

最后就是获取那两个加密参数:

# 获取参数

def get_params(page):

    # msg也可以写成msg = {"offset":"页面偏移量=(页数-1) * 20", "limit":"20"},offset和limit这两个参数必须有(js)

    # limit最大值为100,当设为100时,获取第二页时,默认前一页是20个评论,也就是说第二页最新评论有80个,有20个是第一页显示的

    # 偏移量

    offset = (page-1) * 20

    # offset和limit是必选参数,其他参数是可选的,其他参数不影响data数据的生成,最好还是保留

    msg = '{"offset":' + str(offset) + ',"total":"True","limit":"20","csrf_token":""}'

    key = '0CoJUm6Qyw8W8jud'

    f = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'

    e = '010001'

    enctext = AESencrypt(msg, key)

    # 生成长度为16的随机字符串

    i = generate_random_strs(16)

    # 两次AES加密之后得到params的值

    encText = AESencrypt(enctext, i)

    # RSA加密之后得到encSecKey的值

    encSecKey = RSAencrypt(i, e, f)

    return encText, encSecKey


四,获取全部评论

上面我们获取到了两个参数encText和encSecKey,利用这两个参数来构造post表单数据(Form Data),即data的值:

params, encSecKey = get_params(page)

data = {'params': params, 'encSecKey': encSecKey}


歌曲评论的URL为:


url = 'https://music.163.com/weapi/v1/resource/comments/R_SO_4_' + str(songid) + '?csrf_token='


然后把data加到post的参数中去就能获取到json格式的评论数据.


html = requests.post(url, headers=headers, data=data)


至此,获取网易云音乐全部评论的Python爬虫实现原理分析全部完成!若想获取全部代码请上我的Github:获取网易云音乐歌曲全部评论代码(链接:https://github.com/zyingzhou/music163-spiders/blob/master/get_comments.py)


系列网易云音乐评论爬虫(1):全部热门歌曲及其 id 号



【作者简介】


作者:志颖,一个狂热的 python 爬虫爱好者。

【关于投稿】


如果大家有原创好文投稿,请直接给公号发送留言。


① 留言格式:
【投稿】+《 文章标题》+ 文章链接

② 示例:
【投稿】《不要自称是程序员,我十多年的 IT 职场总结》:

http://blog.jobbole.com/94148/

③ 最后请附上您的个人简介哈~



看完本文有收获?请转发分享给更多人

关注「Python开发者」,提升Python技能

登录查看更多
0

相关内容

网易云音乐是一款专注于发现与分享的音乐产品,依托专业音乐人、DJ、好友推荐及社交功能,为用户打造全新的音乐生活。
【实用书】学习用Python编写代码进行数据分析,103页pdf
专知会员服务
192+阅读 · 2020年6月29日
【2020新书】从Excel中学习数据挖掘,223页pdf
专知会员服务
90+阅读 · 2020年6月28日
【2020新书】使用高级C# 提升你的编程技能,412页pdf
专知会员服务
57+阅读 · 2020年6月26日
还在修改博士论文?这份《博士论文写作技巧》为你指南
干净的数据:数据清洗入门与实践,204页pdf
专知会员服务
161+阅读 · 2020年5月14日
【干货书】流畅Python,766页pdf,中英文版
专知会员服务
224+阅读 · 2020年3月22日
【经典书】Python数据数据分析第二版,541页pdf
专知会员服务
192+阅读 · 2020年3月12日
知识神经元网络 KNN(简介),12页pdf
专知会员服务
14+阅读 · 2019年12月25日
PC微信逆向:两种姿势教你解密数据库文件
黑客技术与网络安全
16+阅读 · 2019年8月30日
GitHub 热门:各大网站的 Python 爬虫登录汇总
机器学习算法与Python学习
9+阅读 · 2019年3月20日
比Selenium快100倍的方法爬东方财富网财务报表
程序人生
8+阅读 · 2018年10月31日
我是一个爬虫
码农翻身
12+阅读 · 2018年6月4日
Python 爬虫实践:《战狼2》豆瓣影评分析
数据库开发
5+阅读 · 2018年3月19日
《小美好》短评文本情感分析+生成词云
数据挖掘入门与实战
5+阅读 · 2018年1月7日
教你用Python爬虫股票评论,简单分析股民用户情绪
数据派THU
10+阅读 · 2017年12月12日
【python 自然语言处理】对胡歌【猎场】电视剧评论进行情感值分析
用 Scikit-Learn 和 Pandas 学习线性回归
Python开发者
9+阅读 · 2017年9月26日
33款可用来抓数据的开源爬虫软件工具 (推荐收藏)
数据科学浅谈
7+阅读 · 2017年7月29日
Meta-Learning with Implicit Gradients
Arxiv
13+阅读 · 2019年9月10日
Next Item Recommendation with Self-Attention
Arxiv
5+阅读 · 2018年8月25日
Feature Selection Library (MATLAB Toolbox)
Arxiv
7+阅读 · 2018年8月6日
VIP会员
相关VIP内容
【实用书】学习用Python编写代码进行数据分析,103页pdf
专知会员服务
192+阅读 · 2020年6月29日
【2020新书】从Excel中学习数据挖掘,223页pdf
专知会员服务
90+阅读 · 2020年6月28日
【2020新书】使用高级C# 提升你的编程技能,412页pdf
专知会员服务
57+阅读 · 2020年6月26日
还在修改博士论文?这份《博士论文写作技巧》为你指南
干净的数据:数据清洗入门与实践,204页pdf
专知会员服务
161+阅读 · 2020年5月14日
【干货书】流畅Python,766页pdf,中英文版
专知会员服务
224+阅读 · 2020年3月22日
【经典书】Python数据数据分析第二版,541页pdf
专知会员服务
192+阅读 · 2020年3月12日
知识神经元网络 KNN(简介),12页pdf
专知会员服务
14+阅读 · 2019年12月25日
相关资讯
PC微信逆向:两种姿势教你解密数据库文件
黑客技术与网络安全
16+阅读 · 2019年8月30日
GitHub 热门:各大网站的 Python 爬虫登录汇总
机器学习算法与Python学习
9+阅读 · 2019年3月20日
比Selenium快100倍的方法爬东方财富网财务报表
程序人生
8+阅读 · 2018年10月31日
我是一个爬虫
码农翻身
12+阅读 · 2018年6月4日
Python 爬虫实践:《战狼2》豆瓣影评分析
数据库开发
5+阅读 · 2018年3月19日
《小美好》短评文本情感分析+生成词云
数据挖掘入门与实战
5+阅读 · 2018年1月7日
教你用Python爬虫股票评论,简单分析股民用户情绪
数据派THU
10+阅读 · 2017年12月12日
【python 自然语言处理】对胡歌【猎场】电视剧评论进行情感值分析
用 Scikit-Learn 和 Pandas 学习线性回归
Python开发者
9+阅读 · 2017年9月26日
33款可用来抓数据的开源爬虫软件工具 (推荐收藏)
数据科学浅谈
7+阅读 · 2017年7月29日
Top
微信扫码咨询专知VIP会员