美文网首页
Scrapy爬取网易云音乐和评论(五、评论)

Scrapy爬取网易云音乐和评论(五、评论)

作者: 苏酒酒 | 来源:发表于2017-11-30 16:53 被阅读0次

    目录:

    1、Scrapy爬取网易云音乐和评论(一、思路分析)
    2、Scrapy爬取网易云音乐和评论(二、Scrapy框架每个模块的作用)
    3、Scrapy爬取网易云音乐和评论(三、爬取歌手)
    4、Scrapy爬取网易云音乐和评论(四、关于API)
    5、Scrapy爬取网易云音乐和评论(五、评论)

    评论的API的参考链接:

    1、https://github.com/darknessomi/musicbox/wiki/%E7%BD%91%E6%98%93%E4%BA%91%E9%9F%B3%E4%B9%90%E6%96%B0%E7%89%88WebAPI%E5%88%86%E6%9E%90%E3%80%82(这个是从歌单下手的,里面的评论可以参考)
    2、http://www.imooc.com/article/17459?block_id=tuijian_wz
    3、http://blog.csdn.net/u012104691/article/details/53766045
    后面这几篇都讲的比较详细,当时查资料的时候,还查到另外一种写法,就是里面有一堆命名是first_param什么的,看得头晕眼花,然后当时测试似乎也没有成功,建议用现在的这种就好了。

    基本模式就是这样:


    来自https://github.com/darknessomi/musicbox/wiki/%E7%BD%91%E6%98%93%E4%BA%91%E9%9F%B3%E4%B9%90%E6%96%B0%E7%89%88WebAPI%E5%88%86%E6%9E%90%E3%80%82

    因为专辑和歌曲都有评论,所以我专门将它写成了个类,后面直接调用就可以了。

    # -*-coding:utf-8-*-
    import os
    import re
    import sys
    import json
    import base64
    import binascii
    import hashlib
    import requests
    from Crypto.Cipher import AES
    
    class CommentCrawl(object):
        '''评论的API封装成一个类,直接传入评论的API,再调用函数get_song_comment()和get_album_comment()即可分别获取歌曲和专辑的评论信息
        '''
    
        def __init__(self,comment_url):
            self.comment_url = comment_url
            self.headers = {
                "Referer":"http://music.163.com",
                "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3067.6 Safari/537.36",
            }
    
        def createSecretKey(self,size):
            '''生成长度为16的随机字符串作为密钥secKey
            '''
            return (''.join(map(lambda xx: (hex(ord(xx))[2:]), os.urandom(size))))[0:16]
    
        def AES_encrypt(self,text, secKey):
            '''进行AES加密
            '''
            pad = 16 - len(text) % 16
            text = text + pad * chr(pad)
            encryptor = AES.new(secKey, 2, '0102030405060708')
            encrypt_text = encryptor.encrypt(text.encode())
            encrypt_text = base64.b64encode(encrypt_text)
            return encrypt_text
    
        def rsaEncrypt(self, text, pubKey, modulus):
            '''进行RSA加密
            '''
            text = text[::-1]
            rs = int(text.encode('hex'), 16) ** int(pubKey, 16) % int(modulus, 16)
            return format(rs, 'x').zfill(256)
    
        def encrypted_request(self, text):
            '''将明文text进行两次AES加密获得密文encText,
            因为secKey是在客户端上生成的,所以还需要对其进行RSA加密再传给服务端。
            '''
            pubKey = '010001'
            modulus = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'
            nonce = '0CoJUm6Qyw8W8jud'
    
            text = json.dumps(text)
            secKey = self.createSecretKey(16)
            encText = self.AES_encrypt(self.AES_encrypt(text, nonce), secKey)
            encSecKey = self.rsaEncrypt(secKey, pubKey, modulus)
            data = {
                'params': encText,
                'encSecKey': encSecKey
            }
            return data   
    
        def get_post_req(self, url, data):
            try:
                req = requests.post(url, headers=self.headers, data=data)
            except Exception,e:
                # dosomething
                print url,e
                # return None
            return req.json()            
    
        def get_offset(self, offset=0):
            '''偏移量
            '''
            if offset == 0:
                text = {'rid':'', 'offset':'0', 'total':'true', 'limit':'20', 'csrf_token':''} 
            else:
                text = {'rid':'', 'offset':'%s' % offset, 'total':'false', 'limit':'20', 'csrf_token':''} 
            return text
    
        def get_json_data(self,url,offset):
            '''json 格式的评论
            '''
            text = self.get_offset(offset)
            data = self.encrypted_request(text)
            json_text = self.get_post_req(url, data)
            return json_text
    
        def get_song_comment(self):
            '''某首歌下全部评论
            '''
            comment_info = []
            data = self.get_json_data(self.comment_url,offset=0)
            comment_count = data['total']
            if comment_count:
                comment_info.append(data)
                if comment_count > 20:
                    for offset in range(20,int(comment_count),20):
                        comment = self.get_json_data(self.comment_url,offset=offset)
                        comment_info.append(comment)
            return comment_info
    
        def get_album_comment(self,comment_count):
            '''某专辑下全部评论
            '''
            album_comment_info = []
            if comment_count:
                for offset in range(0,int(comment_count),20):
                    comment = self.get_json_data(self.comment_url,offset=offset)
                    album_comment_info.append(comment)
            return album_comment_info
    

    重复的地方我就不赘述了,最后两个地方我之所以分开写,是因为专辑的评论数可以从专辑信息里获取,但歌曲评论数从专辑列表信息里获取不到,只能先爬取它第一页的json数据,它里面的total就是评论总数,然后再做后面的处理。

    评论的API:

    # 1、专辑评论API:
    comment_url = 'http://music.163.com/weapi/v1/resource/comments/R_AL_3_%s?csrf_token=' % album_id
    # 2、歌曲评论API:
    comment_url = 'http://music.163.com/weapi/v1/resource/comments/R_SO_4_%s?csrf_token=' % song_id
    

    然后将comment_url 作为参数传入上面封装的那个类里即可,不同的是专辑还需先获取专辑评论的数量。

    所有的分析都结束了,接下来的代码自己写吧。

    相关文章

      网友评论

          本文标题:Scrapy爬取网易云音乐和评论(五、评论)

          本文链接:https://www.haomeiwen.com/subject/pfovbxtx.html