全部代码
import os import json import requests from tkinter import * class couldmusic(object): def __init__(self, tk_root): """初始化""" self.root = tk_root self.playlist_id = StringVar() # 歌单ID,可以通过网易云歌单详情页面获地址栏取 self.song_id = StringVar() # 歌曲ID,可以通过歌曲播放页面地址栏获取 self.song_name = StringVar() # 歌曲名字,用于显示下载信息 self.song_name.set("") self.var = StringVar() # 下载进度值 self.var.set("开始") self.index = 0 self.song_list = {} self.save_path = os.path.abspath(".") # 获取工作目录 self.save_path = os.path.join(self.save_path, "网易云音乐") # 生成网易云音乐文件夹路径 # 浏览器Headers信息 self.headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36", } # 绘制UI self.layout() def process(self): """下载进度条""" total_length = 260 # 进度条总长度 if len(self.song_list) > 0: # 判断歌曲列表非空 length = total_length * self.index / len(self.song_list) # 计算下载进度长度 self.canvas.coords(self.processbar, (0, 0, length,26)) # 创建进度条(起始X坐标,起始Y坐标, 长度,高度) self.var.set(f"{self.index}/{len(self.song_list)}") # 设定进度值 if length == total_length: # 判断是否下载完成 self.song_name.set("下载完成") self.root.update() def reset(self): """重置""" self.song_id.set("") self.playlist_id.set("") self.song_list.clear() self.var.set("开始") self.index = 0 self.save_path = os.path.abspath(".") self.save_path = os.path.join(self.save_path, "网易云音乐") def get_playlist(self, playlist_id): playlist_api = "http://music.163.com/api/playlist/detail?id=" # 歌单详情API playlist_url = playlist_api + playlist_id # 获取歌单详情地址 r = requests.get(playlist_url, headers = self.headers) # 获取源码 json_data = json.loads(r.text) # 源码转换Json格式 # 尝试提取指定信息 try: song_list_name = json_data['result']['creator']['nickname'] # 提取歌单名字 self.song_name.set(f"{song_list_name} 的歌单") self.save_path = os.path.join(self.save_path, song_list_name) # 生成歌单文件路径 if not os.path.isdir(self.save_path): # 判断路径是否存在 os.mkdir(self.save_path) # 创建歌单文件夹 except: self.song_name.set("请输入有效的歌单ID或歌曲ID") return # 提取歌曲信息 for i in json_data['result']['tracks']: song_name = i["name"].split("/")[0] # 获取歌曲名字,并移除 "/" song_id = i['id'] # 获取歌曲ID信息 self.song_list[song_name] = song_id # 将歌曲信息加入到字典备用 return song_list_name def get_song_info(self, song_id): """获取单首歌曲信息""" song_detail_api = "http://music.163.com/api/song/detail/?id=song_id&ids=%5Bsong_id%5D" # 歌曲信息API song_url = song_detail_api.replace("song_id", self.song_id.get()) # 生成歌曲信息Url r = requests.get(song_url, headers = self.headers) # 获取源码 json_data = json.loads(r.text) # 源码转换Json格式 # 尝试提取指定信息 try: for i in json_data['songs']: # 获取Json_data中 ‘songs’内容 self.song_list[i['name']] = self.song_id.get() # 将歌曲信息加入到字典备用 except: self.song_name.set("请输入有效的歌单ID或歌曲ID_2") def download(self): """下载 "self.song_list" 中歌曲""" api = "http://music.163.com/song/media/outer/url?id=song_id.mp3" # api = "https://www.apicp.cn/API/wyy/api.php?id=" # 网易云解析API, 第三方提供 self.index = 0 for item in self.song_list: # 遍历歌曲列表 self.index += 1 # 歌曲次序 song_url = api.replace("song_id", str(self.song_list[item])) # 解析地址 name = item + ".mp3" # 歌曲名字 split_list = ["<", ">", "/", "\\"] # Windows名字机制,移除特殊字符 for x in split_list: name = name.split(x)[0] path = os.path.join(self.save_path, name) # 歌曲保存路径 self.song_name.set(name) # 更新UI信息 content = requests.get(song_url, headers = self.headers).content # 获取源码 if content[0] != 0x49: # 判断返回值是否属于音频文件 self.song_name.set("灰色歌曲无法下载") # 灰色歌曲无法下载 continue # 跳出本次循环 if not os.path.isfile(path): # 判断文件是否存在 with open(path, "wb") as f: # 保存文件 f.write(content) self.process() def run(self): """获取输入信息, 并执行程序""" playlist_id = self.playlist_id.get() # 获取页面输入歌单ID信息 song_id = self.song_id.get() # 获取页面输入歌曲ID信息 if not os.path.isdir(self.save_path): # 判断路径是否存在 os.mkdir(self.save_path) # 创建文件夹 # 判断输入歌单ID和歌曲ID有效 if playlist_id == "" and song_id == "": # 判断歌单/歌曲非空 self.song_name.set("请输入有效的歌单ID或歌曲ID_1") return elif playlist_id: # 歌单ID非空,执行歌单处理函数 self.get_playlist(playlist_id) elif song_id: # 歌曲ID非空,执行歌曲处理函数 self.get_song_info(song_id) self.download() # 执行歌曲下载函数 self.reset() # 重置 def layout(self): """绘制界面""" self.root.title("网易云下载器") # 标题 self.root.geometry("260x100+600+300") # 位置 self.root.bind("<Return>", lambda x:self.run()) # 绑定回车键 # 歌单ID Label(self.root, text = "歌单ID:").grid(row = 0, column = 0) Entry(self.root, textvariable = self.playlist_id).grid(row = 0, column =1, sticky=N+E+S+W) # 歌曲ID Label(self.root, text = "歌曲ID:").grid(row = 1, column =0) Entry(self.root, textvariable = self.song_id).grid(row = 1,column = 1, sticky=N+E+S+W) # 正在下载的歌曲信息 Label(self.root, text = "正在下载:").grid(row = 2, column =0) Entry(self.root, textvariable = self.song_name).grid(row = 2,column = 1, sticky=N+E+S+W) # 进度条 self.canvas = Canvas(self.root,height=26, bg="white") self.canvas.grid(row = 3, column = 1) self.processbar = self.canvas.create_rectangle(0,0,0,0,width = 0,fill = "green") # 开始 Button(self.root, textvariable = self.var, command = self.run).grid(row = 3, column = 0, sticky=N+E+S+W) if __name__ == "__main__": root = Tk() couldmusic(root) root.mainloop()