import requests
import json
import os
import pprint
from urllib import parse
import base64
from Crypto.Cipher import AES
second_param = "010001"
third_param = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
forth_param = "0CoJUm6Qyw8W8jud"
#======知乎大佬给出的搜索歌曲加密函数======#
def pkcs7padding(text):
"""
明文使用PKCS7填充
最终调用AES加密方法时,传入的是一个byte数组,要求是16的整数倍,因此需要对明文进行处理
:param text: 待加密内容(明文)
:return:
"""
bs = AES.block_size # 16
length = len(text)
bytes_length = len(bytes(text, encoding='utf-8'))
# tips:utf-8编码时,英文占1个byte,而中文占3个byte
padding_size = length if(bytes_length == length) else bytes_length
padding = bs - padding_size % bs
# tips:chr(padding)看与其它语言的约定,有的会使用'\0'
padding_text = chr(padding) * padding
return text + padding_text
def aes_en(text,key,iv):
#print('pkcs7padding处理之前:',text)
text =pkcs7padding(text)
#print('pkcs7padding处理之后:',text)
#entext = text + ('\0' * add)
# 初始化加密器
aes = AES.new(key.encode(encoding='utf-8'), AES.MODE_CBC, iv)
enaes_text = str(base64.b64encode(aes.encrypt(str.encode(text))),encoding='utf-8')
return enaes_text
def get_params(first_param):
iv = b"0102030405060708"
first_key = forth_param
second_key = 16 * 'F'
h_encText = aes_en(first_param, first_key, iv)
h_encText = aes_en(h_encText, second_key, iv)
return h_encText
#========================================#
#=====最简单的bug级api,该api未被加密======#
def get_comments_easiestAPI(music_name,music_place):
music_id = get_id(music_name,music_place)
base_url = 'http://music.163.com/api/v1/resource/comments/R_SO_4_' + str(music_id) + '?limit=20&offset='
# http://music.163.com/api/v1/resource/comments/R_SO_4_516997458?limit=20&offset=40
# limit和offset就是改变页数的参数,我在代码注释里面写的有,limit是每页获取的(最大)评论数,offset就是(评论页数-1) * 20
try:
os.remove('网易云' + music_name + '评论.txt')
except FileNotFoundError:
pass
headers = {'User-Agent':'firefox'}
res = requests.get(base_url,headers = headers)
comments_json = json.loads(res.text)
save_comments(comments_json,music_name,comment_key = 'hotComments')
for i in range(1,100):
url = base_url + str(20*(i-1))
res = requests.get(url,headers = headers)
comments_json = json.loads(res.text)
save_comments(comments_json,music_name,comment_key = 'comments')
print('爬取完毕!')
#========================================#
#==============抓取歌曲id函数=============#
def get_id(music_name,music_place):
url = 'https://music.163.com/weapi/cloudsearch/get/web?csrf_token='
headers = {'User-agent':'firefox'}
search_name = music_name
page = "0" #必须是30的整数倍,因为下面first_param参数中的limit值为30,意思是每页最多显示30个评论
first_param = "{"hlpretag":"<span class=\\"s-fc7\\">","hlposttag":"</span>","s":"%s","type":"1","offset":"%s","total":"%s","limit":"30","csrf_token":""}" %(search_name,page,True)
params = get_params(first_param)
data = {'params':params,
'encSecKey':'257348aecb5e556c066de214e531faadd1c55d814f9be95fd06d6bff9f4c7a41f831f6394d5a3fd2e3881736d94a02ca919d952872e7d0a50ebfa1769a7a62d512f5f1ca21aec60bc3819a9c3ffca5eca9a0dba6d6f7249b06f5965ecfff3695b54e1c28f3f624750ed39e7de08fc8493242e26dbc4484a01c76f739e135637c'
}
res = requests.post(url,headers = headers,data = data)
music = json.loads(res.text)
music_id = music['result']['songs'][music_place-1]['id']
print('歌曲id:', music_id)
return music_id
#=========================================#
#=============保存评论函数================#
def save_comments(comment_json,music_name,comment_key):
with open('网易云' + music_name + '评论.txt','a',encoding = 'utf-8') as f:
if(comment_key == 'hotComments'):
f.write('热门评论\n')
if(comment_key == 'comments'):
f.write('\n\n\n最新评论\n')
state = 0
for each in comment_json[comment_key]:
f.write(each['user']['nickname'] + ' :')
f.write(each['content'])
f.write('\n')
#========================================#
#====使用还可以用的旧api,同样被加密过======#
#问题:无法爬取全部最新评论
def get_comments_oldAPI(music_name,music_place):
music_id = get_id(music_name, music_place)
try:
os.remove('网易云' + music_name + '评论.txt')
except FileNotFoundError:
pass
first_param = '{rid:"", offset:"0", total:"true", limit:"20", csrf_token:""}'
#offset就是(评论页数-1) * 20,total在第一页是true,其余是false
headers = {'user-agent':'Firefox'}
params = get_params(first_param)
encSecKey = '257348aecb5e556c066de214e531faadd1c55d814f9be95fd06d6bff9f4c7a41f831f6394d5a3fd2e3881736d94a02ca919d952872e7d0a50ebfa1769a7a62d512f5f1ca21aec60bc3819a9c3ffca5eca9a0dba6d6f7249b06f5965ecfff3695b54e1c28f3f624750ed39e7de08fc8493242e26dbc4484a01c76f739e135637c'
data = {'params' : params,'encSecKey' : encSecKey}
url = 'http://music.163.com/weapi/v1/resource/comments/R_SO_4_' + str(music_id) + '/?csrf_token='
res = requests.post(url,headers = headers,data = data)
comments_json = json.loads(res.text)
save_comments(comments_json,music_name,comment_key = 'hotComments')
for i in range(1,10):
offset = (i-1)*20
first_param = "{rid:"", offset:"%s", total:"false", limit:"20", csrf_token:""}" % offset
print(first_param)
params = get_params(first_param)
res = requests.post(url,headers = headers,data = data)
comments_json = json.loads(res.text)
save_comments(comments_json,music_name,comment_key = 'comments')
print('评论下载成功')
#===========最新版API============#
#url = 'https://music.163.com/weapi/comment/resource/comments/get?csrf_token='
#暂时没有人研究,好像非常不好用
#===============================#
#==========下载网页用的函数==============#
def get_webpage(url):
headers = {'user-agent':'firefox'}
res = requests.get(url,
headers = headers)
with open('Page.txt','w',encoding = 'utf-8') as f:
f.write(res.text)
#=======================================#
def main():
# url = 'https://music.163.com/#/song?id=4466775'
# get_webpage(url)
#music_name = 'lostrivers'
# get_id(music_name)
music_name = input('请输入搜索名称:')
music_place = int(input('请输入第几首歌:'))
# get_comments_easiestAPI(music_name,music_place) #最容易的API
get_comments_oldAPI(music_name,music_place) #旧版API
if __name__ == '__main__':
main()
使用该api(小甲鱼老师的API)进行爬取最新评论时出现了结果,但只有第一页的新评,然而按照代码注释给出的方法无法翻页,应该怎样才能改变参数,进行翻页?