Python利用网易云音乐接口搭建的音乐推荐,根据单曲歌名推荐相关用户喜爱的歌曲

编程入门 行业动态 更新时间:2024-10-08 10:53:14

Python利用网易云音乐接口搭建的音乐推荐,根据<a href=https://www.elefans.com/category/jswz/34/1763917.html style=单曲歌名推荐相关用户喜爱的歌曲"/>

Python利用网易云音乐接口搭建的音乐推荐,根据单曲歌名推荐相关用户喜爱的歌曲

转载自:

一、网易云音乐的相关接口

这边我想要的数据接口有:

* 网易的搜索功能,根据歌名获取歌曲的id

* 歌曲相关的评论用户接口

* 用户的相关数据包括歌单或听歌记录,这边听歌记录的接口好像不能用,所以我就用的歌单接口

关于每个接口大家可以自己F12网易官网看看是长什么样子,网易的新接口加密方式我也是在网上找的资料。

这边就是接口部分的代码:

import requests
import json
import os
import base64
import binascii
from Crypto.Cipher import AES
class NetEaseAPI: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','Referer': '/','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'  # NOQA}self.cookies = {'appver': '1.5.2'}self.playlist_class_dict = {}self.session = requests.Session()def httpRequest(self, method, action, query=None, urlencoded=None, callback=None, timeout=None):connection = json.loads(self.rawHttpRequest(method, action, query, urlencoded, callback, timeout))return connectiondef rawHttpRequest(self, method, action, query=None, urlencoded=None, callback=None, timeout=None):if method == 'GET':url = action if query is None else action + '?' + queryconnection = self.session.get(url)elif method == 'POST':connection = self.session.post(action, query, self.header)elif method == 'Login_POST':connection = self.session.post(action,  query, self.header)self.session.cookies.save()connection.encoding = 'UTF-8'return connection.textdef search(self, s, stype=1, offset=0, total='true', limit=1):action = ''data = {'s': s,'type': stype,'offset': offset,'total': total,'limit': limit}return self.httpRequest('POST', action, data)def aesEncrypt(self, text, secKey):pad = 16 - len(text) % 16text = text + chr(pad) * padencryptor = AES.new(secKey, 2, '0102030405060708')ciphertext = encryptor.encrypt(text)ciphertext = base64.b64encode(ciphertext).decode('utf-8')return ciphertextdef rsaEncrypt(self, 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(self,size):return (''.join(map(lambda xx: (hex(ord(xx))[2:]), os.urandom(size))))[0:16]def encrypted_request(self, text):modulus = ('00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7''b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280''104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932''575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b''3ece0462db0a22b8e7')nonce = '0CoJUm6Qyw8W8jud'pubKey = '010001'text = json.dumps(text)secKey = binascii.hexlify(os.urandom(16))[:16]encText = self.aesEncrypt(self.aesEncrypt(text, nonce), secKey)encSecKey = self.rsaEncrypt(secKey, pubKey, modulus)data = {'params': encText, 'encSecKey': encSecKey}return datadef getComment(self, songId, offset=0, total='fasle', limit=100):action = '{}/?rid=R_SO_4_{}&\offset={}&total={}&limit={}'.format(songId, songId, offset, total, limit)comments = self.httpRequest('GET', action)return comments['hotComments']def getPlaylist(self, uid):text = {'uid': uid,'limit':100}text = json.dumps(text)nonce = '0CoJUm6Qyw8W8jud'pubKey = '010001'modulus = ('00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7''b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280''104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932''575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b''3ece0462db0a22b8e7')secKey = self.createSecretKey(16)encText = self.aesEncrypt(self.aesEncrypt(text, nonce), secKey)encSecKey = self.rsaEncrypt(secKey, pubKey, modulus)data = {'params': encText,'encSecKey': encSecKey}action = '='playlist = self.httpRequest('POST', action, data)res = list()for play in playlist['playlist']:res.append({'id':play['id'],'subscribedCount':play['subscribedCount'],'playCount':play['playCount']})return resdef getPlaylistDetail(self, id):text = {'id': id,'limit':100,'total':True}text = json.dumps(text)nonce = '0CoJUm6Qyw8W8jud'pubKey = '010001'modulus = ('00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7''b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280''104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932''575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b''3ece0462db0a22b8e7')secKey = self.createSecretKey(16)encText = self.aesEncrypt(self.aesEncrypt(text, nonce), secKey)encSecKey = self.rsaEncrypt(secKey, pubKey, modulus)data = {'params': encText,'encSecKey': encSecKey}action = '='playlistDetail = self.httpRequest('POST', action, data)music = list()musicCount = dict()for count in playlistDetail['playlist']['trackIds']:musicCount[count['id']] = count['v']for detail in playlistDetail['playlist']['tracks']:singer = ''for author in detail['ar']:singer += author['name']+','music.append({'id':detail['id'],'name':detail['name'],'singer':singer, 'playCount':musicCount[detail['id']]})return music

二、推荐的逻辑

这边我获取这首歌的所有热门评论用户以及他们的歌单,在获取所有歌单的数据,将歌单中的所有歌曲根据歌单的听取次数、订阅人数、歌曲的听取次数等等进行加权评分,奖所有的歌曲按照分数高低选取其中前30首进行推荐

下面就是评分的代码:

from __future__ import division
import time
from NetEaseAPI import *
class musicRecom():def getSongId(self,musicTitle):  res = NetEaseAPI().search(musicTitle)return res['result']['songs'][0]['id']def musicRank(self,musicDict):maxSubCount = 0maxLsitCount = 0maxMusicCount = 0for music in musicDict:if musicDict[music]['listSubscribedCount'] > maxSubCount :maxSubCount = musicDict[music]['listSubscribedCount'] if musicDict[music]['listCount'] > maxLsitCount :maxLsitCount = musicDict[music]['listCount']if musicDict[music]['musicPlayCount'] > maxMusicCount :maxMusicCount = musicDict[music]['musicPlayCount']for music in musicDict:musicDict[music]['score'] = musicDict[music]['listSubscribedCount'] / maxSubCount + musicDict[music]['listCount'] / maxLsitCount + musicDict[music]['musicPlayCount'] / maxMusicCountreturn sorted(musicDict.items(), key = lambda d:d[1]['score'], reverse = True)

三、界面

为了可以方便输入某首歌名从而进行推荐,我写了一个简单的操作界面,tkinter库,比较丑,这个库不怎么会用,没有怎么写过界面

界面以及事件代码:

from __future__ import division
from Tkinter import *
import Tkinter
import ttk
from musicRecom import *
import threading
class GUI(Frame):def __init__(self, master = None):Frame.__init__(self, master)self.pack()self.create()def progress(self,count1,count2):self.len1.set(count1)self.len2.set(count2)def search(self):musicTitle = self.musicTitle.get()if musicTitle == '':print "Please input the music title!"else:self.len1 = StringVar()self.len2 = StringVar()self.scale1 = Scale(self,from_ = 0,to = 100, resolution = 0.1, orient = HORIZONTAL,variable = self.len1,length = 500).grid(row = 2,column=0, columnspan=4, padx = 5)self.scale2 = Scale(self,from_ = 0,to = 100, resolution = 0.1, orient = HORIZONTAL,variable = self.len2,length = 500).grid(row = 3,column=0, columnspan=4, padx = 5)threading.Thread(target = self.musicRecom).start()def musicRecom(self):self.searchButton.destroy()musicTitle = self.musicTitle.get()res = dict()songId = musicRecom().getSongId(musicTitle)time.sleep(1)comment = NetEaseAPI().getComment(songId)time.sleep(1)count1 = 0for user in comment:count1 = count1 + 1uid = user['user']['userId']playlist = NetEaseAPI().getPlaylist(uid)time.sleep(1)count2 = 0for table in playlist:count2 = count2 + 1musicDetail = NetEaseAPI().getPlaylistDetail(table['id'])time.sleep(1)self.progress(count1/len(comment)*100,count2/len(playlist)*100)for music in musicDetail:res[music['id']]={'id':music['id'],'name':music['name'],'singer':music['singer'],'musicPlayCount':int(music['playCount']),'listCount':int(table['playCount']),'listSubscribedCount':int(table['subscribedCount'])}self.res = musicRecom().musicRank(res)self.maxPage = 4self.page = 1self.nextButton = Button(self, text='Pre', command=self.Pre)self.nextButton.grid(row = 4,column = 1, padx=5, pady=5)self.nextButton = Button(self, text='Next', command=self.Next)self.nextButton.grid(row = 4,column = 2, padx=5, pady=5)self.frame = Frame(self)self.frame.grid(row = 5,columnspan=4)self.getCont()def getCont(self):index = 1num = 0self.frame.destroy()self.frame = Frame(self)self.frame.grid(row = 5,columnspan=4)for item in self.res:num = num + 1if num > self.page * 15:breakif num <= self.page * 15 and num > (self.page - 1) * 15:                Label(self.frame, text=index + (self.page - 1) * 15).grid(row = index + 4,column=0)Label(self.frame, text=item[1]['name'].encode('utf8')).grid(row = index + 4,column=1)Label(self.frame, text=item[1]['id']).grid(row = index + 4,column=2)Label(self.frame, text=item[1]['singer'].encode('utf8')).grid(row = index + 4,column=3)index = index + 1def Next(self):if self.page < self.maxPage:self.page = self.page + 1else:self.page = 1self.getCont()def Pre(self):if self.page > 1:self.page = self.page - 1else:self.page = self.maxPageself.getCont()def create(self):self.labelName = Label(self, text = "Please input the music name:")self.labelName.grid(row = 0, column = 0)self.musicTitle = StringVar()self.inputName = Entry(self, textvariable = self.musicTitle, width=50)self.inputName.grid(row = 0, column = 1, columnspan=3, padx=5, pady=5)self.searchButton = Button(self, text='Search', command=self.search)self.searchButton.grid(row = 1,column = 1, padx=5, pady=5)

四、主调度

#!/usr/bin/env python
# -*- coding: UTF-8 -*-# from Crawler import *
import sys
from GUI import *
default_encoding = 'utf-8'
if sys.getdefaultencoding() != default_encoding:reload(sys)sys.setdefaultencoding(default_encoding)def main():root = Tkinter.Tk()app = GUI(root)root.geometry('640x560')root.resizable(False, False)app.master.title('网易云音乐的歌曲推荐')app.mainloop()if __name__ == "__main__":main()

五、测试结果

更多推荐

Python利用网易云音乐接口搭建的音乐推荐,根据单曲歌名推荐相关用户喜爱的歌曲

本文发布于:2024-02-14 13:47:06,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1763835.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:单曲   音乐   网易   歌名   喜爱

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!