python爬取网易云音乐评论

    js加密的数据爬取一直都是非常困难的,本来水平就不咋地,决定爬取网易云音乐的评论进行练习。花费了半天功夫才弄好,真的太难了,幸亏有大佬的参考https://www.zhihu.com/question/36081767/answer/386606315,不然根本不可能完成。这篇文章主要是将个解密的思想,当然每个步骤我都会详细说明,从分析api到爬取代码。学习到思路才是最重要的。

    在这里我先讲一下js解密的思想,首先我们会找到加密的参数,然后通过全局搜寻找到相应的js文件,我们可以将js文件拿到本地进行更改,这样的js文件一般代码都是几万行起步,看的头皮发麻,我们通过IDE将代码整理,然后全局搜寻加密参数找到产生他的函数,如果这个函数可以独立运行,我们可以将它拿出来放到本地进行运行,分析结果。另一种是不可以独立运行,需要其他的函数依赖,参数依赖等,很难找到,我们可以通过fiddler进行js文件调换,本文主要用到第二种,废话不多说,开始整。

     一,分析API

        1 查看请求

        通过chrome的f12,调取控制台进行查看是哪个请求得到评论,很简单的找到那个请求,如下图1

python爬取网易云音乐评论_第1张图片

                                                                             图1 

我们看一下它的请求头,如图2,api为https://music.163.com/weapi/v1/resource/comments/R_SO_4_1294910785?csrf_token=

其中那个R_SO_....代表的是歌曲的ID表示.

python爬取网易云音乐评论_第2张图片

                                                                     图2

api为一个post请求,看一下它需要提交的参数,如图3,看到这个就知道是js加密了,直接搞起

                                                                     图3

二,分析js加密                                                                 

           1.寻找js加密文件

           直接crtl+shift+l,进行全局搜索找到了得出两个参数的js文件,如图4,这是一个在core.js文件。

python爬取网易云音乐评论_第3张图片

                                                                                      图4

      2.分析core.js

        通过IDE进行字词搜寻,找到了产生两个参数的函数,这就是产生两个参数的位置。只要知道变量bSm5r就可以揭开谜底。

 

var bSm5r = window.asrsea(JSON.stringify(i5n), bry7r(["流泪", "强"]), bry7r(PI8A.md), bry7r(["爱心", "女孩", "惊恐", "大笑"]));
e5j.data = k5p.cB6v({params: bSm5r.encText, encSecKey: bSm5r.encSecKey})

分析这四个参数是个令人脑壳疼的事情,可能对于精通前端大佬的人来说是小菜一碟,这可咋办。。。。。。。。。。。根据开头我所说的两种方式,显然是第二种比较可靠,开始搞起。

     打开Fiddler,进行js文件调换,将http请求的js文件转到请求本地的js文件,这样我们就可以知道这四个固定的值。

  •       python爬取网易云音乐评论_第4张图片

              底部两行的内容,第一行写http请求的网址,第二个写你保存到本地的js文件,然后点击save,进行保存,将浏览器清除数据,重新请求,那么你会发现请求的js文件就是你本机js文件的内容,这样你想得到什么样的结果就可以得到啥结果了,嘻嘻嘻。

      将四个参数分别输出,如下图,第一个参数就是讲变量类型转化为字符串,重新刷新浏览器,在console里查看结果

python爬取网易云音乐评论_第5张图片

      结果如图所示,结果里面会出现很多这种类型的数据,是因为多个网页会请求这个js文件,显然这个是比较靠谱的一个。

得到了四个参数

first={rid: "R_SO_4_1294910785", offset: "0", total: "true", limit: "20", csrf_token: ""}

second=010001

third=00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7

forth=0CoJUm6Qyw8W8jud

后面的三个值是固定的,,嘻嘻嘻,第一个很显然,一看就知道各个参数的意思,rid是歌曲id,然后limit是评论数,其他没啥意思。知道参数,然后开始分析函数。

 

 

 

想知道bSm5r还需要知道函数 window.asrsea ,再次进行查找,找到了asrsea是哪个函数,如图

,他就是函数function d(),根据wendow.asrsea函数含有四个参数进行判断,找到了

 

3 分析加密js

    我们先一个参数一个参数的开始分析,函数的四个参数是调用函数时的四个变量,根据第二步骤里的代码可以发现这个参数很是奇葩,先看一下里面的内容。i = a(16)  通过查找function a() ,找到他就只是获得一个十六位的随机值,这个我们随意指定一个就行了。比如16个‘F’,如果没有猜错这个enctext就是param,encSeckey就是encSeckey,求出这个就行了。

     encText需要函数b,查看函数b,得到下图,这是一个CBC模式的AES加密(AEC有许多模式,要注意别写错),偏移值为“0102030405060708”,我们要用pyhton进行加密模拟,之后会进行详细解释。

   encText是一个加密了两次的值,我们再来分析encSeckey,他是函数c,三个参数都是固定的,所以这个值我们请求的时候找个就行了,没啥好分析。如图:

现在已经分析出了所以然了,开始python代码

首先需要安装pycrypto这个库,因为这个库已经三四年没有维护,而且如果你不用vs编程的话,安装还需要设置很多东西,我就因为这个浪费很多时间,现在官方使用pycryptodome这个库。最开始那个知乎上大佬应该是pycrypto,我用的是pycryptodome库,如果遇到安装问题自行百度google。

加密的代码,我也是从知乎大佬的代码进行更改了一下,因为安装的库文件的不同,嘻嘻嘻

# coding = utf-8
from Crypto.Cipher import AES
import base64


first_param = '{rid:"", offset:"0", total:"true", limit:"80", csrf_token:""}'
second_param = "010001"
third_param = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
forth_param = "0CoJUm6Qyw8W8jud"


def get_params():
    iv = '0102030405060708'
    first_key = forth_param
    second_key = 16 * 'F'
    h_encText = AES_encrypt(first_param, first_key, iv)
    h_encText = AES_encrypt(h_encText, second_key, iv)
    return h_encText
def get_encSecKey():
    encSecKey = "257348aecb5e556c066de214e531faadd1c55d814f9be95fd06d6bff9f4c7a41f831f6394d5a3fd2e3881736d94a02ca919d952872e7d0a50ebfa1769a7a62d512f5f1ca21aec60bc3819a9c3ffca5eca9a0dba6d6f7249b06f5965ecfff3695b54e1c28f3f624750ed39e7de08fc8493242e26dbc4484a01c76f739e135637c"
    return encSecKey
def AES_encrypt(text, key, iv):

    if type(text)==type(b'123'): #这是判断当前变量的类型是bytes还是字符串,因为pycryptodome要        
                                  #求参数要是字节类型

        text=text.decode('utf-8')
  
    pad = 16 - len(text) % 16    #了解这个加密算法的人应该知道,加密的位数是16的位数,不够的话        
                                 #进行不上,我也不了解这个算法,有兴趣的可以上网查查

    text = text + pad * chr(pad)

    iv=iv.encode('utf-8')
    key=key.encode('utf-8')
    encryptor = AES.new(key, AES.MODE_CBC, iv)
    text=text.encode('utf-8')
    encrypt_text = encryptor.encrypt(text)
    encrypt_text = base64.b64encode(encrypt_text)
    return encrypt_text

if __name__ == "__main__":
   
    params = get_params();
    encSecKey = get_encSecKey();
    print((params).decode('utf-8'))
    print(encSecKey)

 

爬取网易云评论的代码,这个代码很是简陋,毕竟这主要讲的是破解js加密,至于内容你们可以自己进行扩展。

 

# coding = utf-8
from Crypto.Cipher import AES
import base64
import requests
import json

first_param = '{rid:"", offset:"0", total:"true", limit:"80", csrf_token:""}'
second_param = "010001"
third_param = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
forth_param = "0CoJUm6Qyw8W8jud"


headers = {
    'Cookie': 'appver=1.5.0.75771;',
    'Accept-Language':"zh-CN,zh;q=0.9,en;q=0.8",
    'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36',
    'Referer': 'http://music.163.com/'

}

def get_params():
    iv = '0102030405060708'
    first_key = forth_param
    second_key = 16 * 'F'
    h_encText = AES_encrypt(first_param, first_key, iv)
    h_encText = AES_encrypt(h_encText, second_key, iv)
    return h_encText
def get_encSecKey():
    encSecKey = "257348aecb5e556c066de214e531faadd1c55d814f9be95fd06d6bff9f4c7a41f831f6394d5a3fd2e3881736d94a02ca919d952872e7d0a50ebfa1769a7a62d512f5f1ca21aec60bc3819a9c3ffca5eca9a0dba6d6f7249b06f5965ecfff3695b54e1c28f3f624750ed39e7de08fc8493242e26dbc4484a01c76f739e135637c"
    return encSecKey
def AES_encrypt(text, key, iv):

    if type(text)==type(b'123'):

        text=text.decode('utf-8')
    # text=text.decode('utf-8')
    pad = 16 - len(text) % 16

    text = text + pad * chr(pad)

    iv=iv.encode('utf-8')
    key=key.encode('utf-8')
    encryptor = AES.new((key), AES.MODE_CBC, (iv))
    text=text.encode('utf-8')
    encrypt_text = encryptor.encrypt(text)
    encrypt_text = base64.b64encode(encrypt_text)
    return encrypt_text

def get_json(url, params, encSecKey):
    data = {
         "params": params,
         "encSecKey": encSecKey
    }
    response = requests.post(url, headers=headers, data=data)
    return response.content


if __name__ == "__main__":
    url = "http://music.163.com/weapi/v1/resource/comments/R_SO_4_1294910785/?csrf_token="
    params = get_params();
    encSecKey = get_encSecKey();
    print((params).decode('utf-8'))
    print(encSecKey)
    json_text = get_json(url, params, encSecKey)
    json_dict = json.loads(json_text)
    print (json_dict['total'])
    i=0
    for item in json_dict['comments']:
        print (item['content'])
        print(i)
        i+=1



   非常感谢知乎大佬写的https://www.zhihu.com/question/36081767/answer/386606315,毕竟没有这篇文章,我还是不知道该如何解密。希望各位读者也能分享自己学习心得的文章,让我们共同勉励自己。不当之处,欢迎各位指正,通过结合两个文章一起阅读更加,我写的要详细一些,可能表达的不是很好。

 

 

 

 

 

 

你可能感兴趣的:(python爬虫)