Python抓取网页云音乐指定歌手的歌曲和评论数量

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhengxiaojunkite/article/details/48652149

之前简单学了一下Python,没做过东西,心血来潮来了个idea,就写了一个抓取网页云音乐指定歌手的歌曲和评论数量的脚本。

代码如下,如果缺少包则用pip安装一下,不过AES加密用到的pycrypto包,编译安装需要有c++环境,所以建议下载编译好的版本,我这里是Python35的:https://github.com/nsrathjen/pycrypto-py3.5-win64-binary

代码

import os
import json
import hashlib
import base64
import binascii
from Crypto.Cipher import AES
import requests
import prettytable


default_timeout = 100 #定义超时时间


modulus = ('00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7'
           'b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280'
           '104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932'
           '575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b'
           '3ece0462db0a22b8e7')
nonce = '0CoJUm6Qyw8W8jud'
pubKey = '010001'
# 歌曲加密算法, 基于https://github.com/yanunon/NeteaseCloudMusic脚本实现
def encrypted_id(id):
    magic = bytearray('3go8&$8*3*3h0k(2)2', 'u8')
    song_id = bytearray(id, 'cd u8')
    magic_len = len(magic)
    for i, sid in enumerate(song_id):
        song_id[i] = sid ^ magic[i % magic_len]
    m = hashlib.md5(song_id)
    result = m.digest()
    result = base64.b64encode(result)
    result = result.replace(b'/', b'_')
    result = result.replace(b'+', b'-')
    return result.decode('utf-8')




# 加密算法, 基于https://github.com/stkevintan/nw_musicbox脚本实现
def encrypted_request(text):
    text = json.dumps(text)
    secKey = createSecretKey(16)
    encText = aesEncrypt(aesEncrypt(text, nonce), secKey)
    encSecKey = rsaEncrypt(secKey, pubKey, modulus)
    data = {'params': encText, 'encSecKey': encSecKey}
    return data




def aesEncrypt(text, secKey):
    pad = 16 - len(text) % 16
    text = text + chr(pad) * pad
    encryptor = AES.new(secKey, 2, '0102030405060708')
    ciphertext = encryptor.encrypt(text)
    ciphertext = base64.b64encode(ciphertext).decode('utf-8')
    return ciphertext




def rsaEncrypt(text, pubKey, modulus):
    text = text[::-1]
    rs = pow(int(binascii.hexlify(text), 16), int(pubKey, 16), int(modulus, 16))
    return format(rs, 'x').zfill(256)




def createSecretKey(size):
    return binascii.hexlify(os.urandom(size))[:16]




# 此类用了post查询歌曲
class NetEase:
    def __init__(self):
        self.header = {
            'Accept': '*/*',
            'Accept-Encoding': 'gzip,deflate,sdch',
            'Accept-Language': 'zh-CN,zh;q=0.8,gl;q=0.6,zh-TW;q=0.4',
            'Connection': 'keep-alive',
            'Content-Type': 'application/x-www-form-urlencoded',
            'Host': 'music.163.com',
            'Referer': 'http://music.163.com/search/',
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36'
        }
        self.cookies = {'appver': '1.5.2'}


    # 搜索单曲(1),歌手(100),专辑(10),歌单(1000),用户(1002) *(type)*
    def search(self, s, stype=1, offset=0, total='true', limit=100):
        action = 'http://music.163.com/api/search/get/web'
        data = {
            's': s,
            'type': stype,
            'offset': offset,
            'total': total,
            'limit': limit
        }
        return self.httpRequest('POST', action, data)
    ###发起一个http请求
    def httpRequest(self, method, action, query=None, urlencoded=None, callback=None, timeout=None):
        if(method == 'GET'):
            url = action if (query == None) else (action + '?' + query)
            connection = requests.get(url, headers=self.header, timeout=default_timeout)


        else:
            connection = requests.post(
                action,
                data=query,
                headers=self.header,
                timeout=default_timeout
            )


        connection.encoding = "UTF-8"
        connection = json.loads(connection.text)
        return connection
    ####获取评论数量
    def getCommentNum(self, id):
        action = 'http://music.163.com/weapi/v1/resource/comments/R_SO_4_'+str(id)+'?csrf_token='
        csrf = ''
        req = {'csrf_token': csrf}
        data = encrypted_request(req)
        return self.httpRequest('POST', action, data)    


###############################################################################
#配置项
singer = '周杰伦' #歌手
page = 2 #只请求两页数据
limit = 100 #每页的歌曲数量


##########################正文##############################
netEase = NetEase()
musics = netEase.search(singer, stype=1)
songCount = musics['result']['songCount']
#总页数
pageNum =  int(songCount/limit) if songCount%limit==0 else int(songCount/limit)+1
songs = [[]] * (songCount if (page > pageNum) else (page * limit))
number = 0
for currentPage in range(0,pageNum):
    if(currentPage>=page):
        break
    print('正在处理第' + str(currentPage + 1) + '页数据...')
    offset = currentPage*limit
    musics = netEase.search(singer,stype=1,offset=offset,limit=limit)
    count = (songCount-offset) if currentPage==limit else limit
    ###循环获取歌曲评论数量
    for key in range(0,count):
        songId = musics['result']['songs'][key]['id']
        songName = musics['result']['songs'][key]['name']
        result = netEase.getCommentNum(songId)
        commentNum = result['total']
        songs[number] = [songId,songName,singer,commentNum]
        number+=1
songs.sort(key=lambda x:x[3],reverse=True) ##按评论数量逆序
##表格输出结果
table = prettytable.PrettyTable()
table.field_names = ["ID", "歌名", "歌手", "评论数量"]
for number in range(0, 20): ##只展示评论数量前20名的歌曲
    table.add_row([songs[number][0],songs[number][1],songs[number][2],songs[number][3]])
print(table)


效果


展开阅读全文

没有更多推荐了,返回首页