当前位置:   article > 正文

40. 实战:基于tkinter实现用户UI界面——对34小节的VIP音乐解析系统的全面升级(附源码)_self.response_data['data']['list']

self.response_data['data']['list']

目录

前言

目的

思路

代码实现

1. 首先设计主页UI界面

2. 封装核心解析歌曲代码

3. 下载音乐到本地

4. 将界面居中,禁止修改窗口大小,等待关闭/退出指令 

完整源码

运行效果

使用过程

菜单栏

打包的exe

总结


前言

本节将升级34. 实战:基于某api实现歌曲检索与下载(附完整源代码),也将基于api实现视频解析播放的功能,并且还实现了用户UI界面,可以用pyinstaller等库导出exe来永久保存可执行文件。

博主已经成功导出可执行文件,包括上一节的视频解析软件也已经导出。需要的小伙伴可以私信我或者评论区留言,我分享给你~


目的

实现一个VIP音乐解析系统,要求能够通过关键字检索需要的歌曲,并且设计用户界面,进行直观的交互行为,下载到本地同目录下的Download文件夹中。


思路

使用tkinter库设计UI界面并把各组件封装起来,核心功能仍然是34节所讲过的代码部分,传送门在这里,想要了解核心功能的跳转:34. 实战:基于某api实现歌曲检索与下载(附完整源代码)

接下来是详细思路:

1. 首先设计主页UI界面

2. 封装核心解析歌曲代码

3. 下载音乐到本地

4. 将界面居中,禁止修改窗口大小,等待关闭/退出指令 


代码实现

先导包

import os
import tkinter as tk
import webbrowser
import requests
import tkinter.messagebox as mes_box
import PySimpleGUI as sg
from tkinter import ttk
from retrying import retry

1. 首先设计主页UI界面

  1. def __init__(self, weight=1000, height=600):
  2. self.ui_weight = weight
  3. self.ui_height = height
  4. self.title = "Vector的音乐解析器"
  5. self.ui_root = tk.Tk(className=self.title)
  6. self.ui_url = tk.StringVar()
  7. self.ui_var = tk.IntVar()
  8. self.ui_var.set(1)
  9. self.show_result = None
  10. self.song_num = None
  11. self.response_data = None
  12. self.song_url = None
  13. self.song_name = None
  14. self.song_author = None
  15. def set_ui(self):
  16. """
  17. 设置简易UI界面
  18. :return:
  19. """
  20. # Frame空间
  21. frame_1 = tk.Frame(self.ui_root)
  22. frame_2 = tk.Frame(self.ui_root)
  23. frame_3 = tk.Frame(self.ui_root)
  24. frame_4 = tk.Frame(self.ui_root)
  25. # ui界面中菜单设计
  26. ui_menu = tk.Menu(self.ui_root)
  27. self.ui_root.config(menu=ui_menu)
  28. file_menu = tk.Menu(ui_menu, tearoff=0)
  29. ui_menu.add_cascade(label='菜单', menu=file_menu)
  30. file_menu.add_command(label='使用说明', command=lambda: webbrowser.open('www.baidu.com'))
  31. file_menu.add_command(label='关于作者', command=lambda: webbrowser.open(
  32. 'https://blog.csdn.net/m0_59180666?spm=1010.2135.3001.5343'))
  33. file_menu.add_command(label='退出', command=self.ui_root.quit)
  34. # 控件内容设置
  35. choice_passageway = tk.Label(frame_1, text='请选择音乐搜索通道:', padx=10, pady=10)
  36. passageway_button_1 = tk.Radiobutton(frame_1, text='酷我', variable=self.ui_var, value=1, width=10, height=3)
  37. passageway_button_2 = tk.Radiobutton(frame_1, text='网易云', variable=self.ui_var, value=2, width=10, height=3)
  38. passageway_button_3 = tk.Radiobutton(frame_1, text='QQ音乐', variable=self.ui_var, value=3, width=10, height=3)
  39. passageway_button_4 = tk.Radiobutton(frame_1, text='酷狗', variable=self.ui_var, value=4, width=10, height=3)
  40. input_link = tk.Label(frame_2, text="请输入搜索关键词:")
  41. entry_style = tk.Entry(frame_2, textvariable=self.ui_url, highlightcolor='Fuchsia', highlightthickness=1,
  42. width=35)
  43. label2 = tk.Label(frame_2, text=" ")
  44. play_button = tk.Button(frame_2, text="搜索", font=('楷体', 11), fg='Purple', width=2, height=1,
  45. command=self.get_KuWoMusic)
  46. label3 = tk.Label(frame_2, text=" ")
  47. # 表格样式
  48. columns = ("序号", "歌手", "歌曲", "专辑")
  49. self.show_result = ttk.Treeview(frame_3, height=20, show="headings", columns=columns)
  50. # 下载
  51. download_button = tk.Button(frame_4, text="下载", font=('楷体', 11), fg='Purple', width=6, height=1, padx=5,
  52. pady=5, command=self.download_music)
  53. # 控件布局
  54. frame_1.pack()
  55. frame_2.pack()
  56. frame_3.pack()
  57. frame_4.pack()
  58. choice_passageway.grid(row=0, column=0)
  59. passageway_button_1.grid(row=0, column=1)
  60. passageway_button_2.grid(row=0, column=2)
  61. passageway_button_3.grid(row=0, column=3)
  62. passageway_button_4.grid(row=0, column=4)
  63. input_link.grid(row=0, column=0)
  64. entry_style.grid(row=0, column=1)
  65. label2.grid(row=0, column=2)
  66. play_button.grid(row=0, column=3, ipadx=10, ipady=10)
  67. label3.grid(row=0, column=4)
  68. self.show_result.grid(row=0, column=4)
  69. download_button.grid(row=0, column=5)
  70. # 设置表头
  71. self.show_result.heading("序号", text="序号")
  72. self.show_result.heading("歌手", text="歌手")
  73. self.show_result.heading("歌曲", text="歌曲")
  74. self.show_result.heading("专辑", text="专辑")
  75. # 设置列
  76. self.show_result.column("序号", width=100, anchor='center')
  77. self.show_result.column("歌手", width=200, anchor='center')
  78. self.show_result.column("歌曲", width=200, anchor='center')
  79. self.show_result.column("专辑", width=300, anchor='center')
  80. # 鼠标点击
  81. self.show_result.bind('<ButtonRelease-1>', self.get_song_url)

2. 封装核心解析歌曲代码

  1. @retry(stop_max_attempt_number=5)
  2. def get_KuWoMusic(self):
  3. """
  4. 获取qq音乐
  5. :return:
  6. """
  7. # 清空treeview表格数据
  8. for item in self.show_result.get_children():
  9. self.show_result.delete(item)
  10. headers = {
  11. 'accept': 'application/json, text/plain, */*',
  12. 'accept - encoding': 'gzip, deflate',
  13. 'accept - language': 'zh - CN, zh;q = 0.9',
  14. 'cache - control': 'no - cache',
  15. 'Connection': 'keep-alive',
  16. 'csrf': 'HH3GHIQ0RYM',
  17. 'Referer': 'http://www.kuwo.cn/search/list?key=%E5%91%A8%E6%9D%B0%E4%BC%A6',
  18. 'User-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
  19. 'Chrome/99.0.4844.51 Safari/537.36',
  20. 'Cookie': '_ga=GA1.2.218753071.1648798611; _gid=GA1.2.144187149.1648798611; _gat=1; '
  21. 'Hm_lvt_cdb524f42f0ce19b169a8071123a4797=1648798611; '
  22. 'Hm_lpvt_cdb524f42f0ce19b169a8071123a4797=1648798611; kw_token=HH3GHIQ0RYM'
  23. }
  24. search_input = self.ui_url.get()
  25. if len(search_input) > 0:
  26. search_url = 'http://www.kuwo.cn/api/www/search/searchMusicBykeyWord?'
  27. search_data = {
  28. 'key': search_input,
  29. 'pn': '1',
  30. 'rn': '80',
  31. 'httpsStatus': '1',
  32. 'reqId': '858597c1-b18e-11ec-83e4-9d53d2ff08ff'
  33. }
  34. try:
  35. self.response_data = requests.get(search_url, params=search_data, headers=headers, timeout=20).json()
  36. songs_data = self.response_data['data']['list']
  37. if int(self.response_data['data']['total']) <= 0:
  38. mes_box.showerror(title='错误', message='搜索: {} 不存在.'.format(search_input))
  39. else:
  40. for i in range(len(songs_data)):
  41. self.show_result.insert('', i, values=(i + 1, songs_data[i]['artist'], songs_data[i]['name'],
  42. songs_data[i]['album']))
  43. except TimeoutError:
  44. mes_box.showerror(title='错误', message='搜索超时,请重新输入后再搜索!')
  45. else:
  46. mes_box.showerror(title='错误', message='未输入需查询的歌曲或歌手,请输入后搜索!')
  47. def get_song_url(self, event):
  48. """
  49. 获取下载歌曲的地址
  50. :return:
  51. """
  52. # treeview中的左键单击
  53. for item in self.show_result.selection():
  54. item_text = self.show_result.item(item, "values")
  55. # 获取
  56. self.song_num = int(item_text[0])
  57. # 获取下载歌曲的地址
  58. if self.song_num is not None:
  59. songs_data = self.response_data['data']['list']
  60. songs_req_id = self.response_data['reqId']
  61. song_rid = songs_data[self.song_num - 1]['rid']
  62. music_url = 'http://www.kuwo.cn/api/v1/www/music/playUrl?mid={}&type=convert_url3' \
  63. '&httpsStatus=1&reqId={}' \
  64. .format(song_rid, songs_req_id)
  65. response_data = requests.get(music_url).json()
  66. self.song_url = response_data['data'].get('url')
  67. self.song_name = songs_data[self.song_num - 1]['name']
  68. self.song_author = songs_data[self.song_num - 1]['artist']
  69. else:
  70. mes_box.showerror(title='错误', message='未选择要下载的歌曲,请选择')

3. 下载音乐到本地

  1. def download_music(self):
  2. """
  3. 下载音乐
  4. :return:
  5. """
  6. if not os.path.exists('./Download'):
  7. os.mkdir("./Download/")
  8. if self.song_num is not None:
  9. song_name = self.song_name + '--' + self.song_author + ".mp3"
  10. try:
  11. save_path = os.path.join('./3_Download/{}'.format(song_name)) \
  12. .replace('\\', '/')
  13. true_path = os.path.abspath(save_path)
  14. resp = requests.get(self.song_url)
  15. with open(save_path, 'wb') as file:
  16. file.write(resp.content)
  17. mes_box.showinfo(title='下载成功', message='歌曲:%s,保存地址为%s' % (self.song_name, true_path))
  18. except Exception:
  19. mes_box.showerror(title='错误', message='未找到存放歌曲的文件夹')
  20. else:
  21. mes_box.showerror(title='错误', message='未选择要下载的歌曲,请选择后下载')
  22. def progress_bar(self, file_size):
  23. """
  24. 任务加载进度条
  25. :return:
  26. """
  27. layout = [[sg.Text('任务完成进度')],
  28. [sg.ProgressBar(file_size, orientation='h', size=(40, 20), key='progressbar')],
  29. [sg.Cancel()]]
  30. # window只需将自定义的布局加载出来即可 第一个参数是窗口标题。
  31. window = sg.Window('机器人执行进度', layout)
  32. # 根据key值获取到进度条
  33. _progress_bar = window['progressbar']
  34. for i in range(file_size): # 循环
  35. event, values = window.read(timeout=10)
  36. if event == 'Cancel' or event is None:
  37. break
  38. _progress_bar.UpdateBar(i + 1)

4. 将界面居中,禁止修改窗口大小,等待关闭/退出指令 

  1. def ui_center(self):
  2. """
  3. UI界面窗口设置:居中
  4. """
  5. ws = self.ui_root.winfo_screenwidth()
  6. hs = self.ui_root.winfo_screenheight()
  7. x = int((ws / 2) - (self.ui_weight / 2))
  8. y = int((hs / 2) - (self.ui_height / 2))
  9. self.ui_root.geometry('{}x{}+{}+{}'.format(self.ui_weight, self.ui_height, x, y))
  10. def loop(self):
  11. """
  12. 函数说明:loop等待用户事件
  13. """
  14. self.ui_root.resizable(False, False) # 禁止修改窗口大小
  15. self.ui_center() # 窗口居中
  16. self.set_ui()
  17. self.ui_root.mainloop()
  18. if __name__ == '__main__':
  19. a = SetUI()
  20. a.loop()

完整源码

  1. # Created at UESTC
  2. # Author: Vector Kun
  3. # Time: 2023/1/29 11:07
  4. import os
  5. import tkinter as tk
  6. import webbrowser
  7. import requests
  8. import tkinter.messagebox as mes_box
  9. import PySimpleGUI as sg
  10. from tkinter import ttk
  11. from retrying import retry
  12. class SetUI(object):
  13. """
  14. 音乐弹框界面
  15. """
  16. def __init__(self, weight=1000, height=600):
  17. self.ui_weight = weight
  18. self.ui_height = height
  19. self.title = "Vector的音乐解析器"
  20. self.ui_root = tk.Tk(className=self.title)
  21. self.ui_url = tk.StringVar()
  22. self.ui_var = tk.IntVar()
  23. self.ui_var.set(1)
  24. self.show_result = None
  25. self.song_num = None
  26. self.response_data = None
  27. self.song_url = None
  28. self.song_name = None
  29. self.song_author = None
  30. def set_ui(self):
  31. """
  32. 设置简易UI界面
  33. :return:
  34. """
  35. # Frame空间
  36. frame_1 = tk.Frame(self.ui_root)
  37. frame_2 = tk.Frame(self.ui_root)
  38. frame_3 = tk.Frame(self.ui_root)
  39. frame_4 = tk.Frame(self.ui_root)
  40. # ui界面中菜单设计
  41. ui_menu = tk.Menu(self.ui_root)
  42. self.ui_root.config(menu=ui_menu)
  43. file_menu = tk.Menu(ui_menu, tearoff=0)
  44. ui_menu.add_cascade(label='菜单', menu=file_menu)
  45. file_menu.add_command(label='使用说明', command=lambda: webbrowser.open('www.baidu.com'))
  46. file_menu.add_command(label='关于作者', command=lambda: webbrowser.open(
  47. 'https://blog.csdn.net/m0_59180666?spm=1010.2135.3001.5343'))
  48. file_menu.add_command(label='退出', command=self.ui_root.quit)
  49. # 控件内容设置
  50. choice_passageway = tk.Label(frame_1, text='请选择音乐搜索通道:', padx=10, pady=10)
  51. passageway_button_1 = tk.Radiobutton(frame_1, text='酷我', variable=self.ui_var, value=1, width=10, height=3)
  52. passageway_button_2 = tk.Radiobutton(frame_1, text='网易云', variable=self.ui_var, value=2, width=10, height=3)
  53. passageway_button_3 = tk.Radiobutton(frame_1, text='QQ音乐', variable=self.ui_var, value=3, width=10, height=3)
  54. passageway_button_4 = tk.Radiobutton(frame_1, text='酷狗', variable=self.ui_var, value=4, width=10, height=3)
  55. input_link = tk.Label(frame_2, text="请输入搜索关键词:")
  56. entry_style = tk.Entry(frame_2, textvariable=self.ui_url, highlightcolor='Fuchsia', highlightthickness=1,
  57. width=35)
  58. label2 = tk.Label(frame_2, text=" ")
  59. play_button = tk.Button(frame_2, text="搜索", font=('楷体', 11), fg='Purple', width=2, height=1,
  60. command=self.get_KuWoMusic)
  61. label3 = tk.Label(frame_2, text=" ")
  62. # 表格样式
  63. columns = ("序号", "歌手", "歌曲", "专辑")
  64. self.show_result = ttk.Treeview(frame_3, height=20, show="headings", columns=columns)
  65. # 下载
  66. download_button = tk.Button(frame_4, text="下载", font=('楷体', 11), fg='Purple', width=6, height=1, padx=5,
  67. pady=5, command=self.download_music)
  68. # 控件布局
  69. frame_1.pack()
  70. frame_2.pack()
  71. frame_3.pack()
  72. frame_4.pack()
  73. choice_passageway.grid(row=0, column=0)
  74. passageway_button_1.grid(row=0, column=1)
  75. passageway_button_2.grid(row=0, column=2)
  76. passageway_button_3.grid(row=0, column=3)
  77. passageway_button_4.grid(row=0, column=4)
  78. input_link.grid(row=0, column=0)
  79. entry_style.grid(row=0, column=1)
  80. label2.grid(row=0, column=2)
  81. play_button.grid(row=0, column=3, ipadx=10, ipady=10)
  82. label3.grid(row=0, column=4)
  83. self.show_result.grid(row=0, column=4)
  84. download_button.grid(row=0, column=5)
  85. # 设置表头
  86. self.show_result.heading("序号", text="序号")
  87. self.show_result.heading("歌手", text="歌手")
  88. self.show_result.heading("歌曲", text="歌曲")
  89. self.show_result.heading("专辑", text="专辑")
  90. # 设置列
  91. self.show_result.column("序号", width=100, anchor='center')
  92. self.show_result.column("歌手", width=200, anchor='center')
  93. self.show_result.column("歌曲", width=200, anchor='center')
  94. self.show_result.column("专辑", width=300, anchor='center')
  95. # 鼠标点击
  96. self.show_result.bind('<ButtonRelease-1>', self.get_song_url)
  97. @retry(stop_max_attempt_number=5)
  98. def get_KuWoMusic(self):
  99. """
  100. 获取qq音乐
  101. :return:
  102. """
  103. # 清空treeview表格数据
  104. for item in self.show_result.get_children():
  105. self.show_result.delete(item)
  106. headers = {
  107. 'accept': 'application/json, text/plain, */*',
  108. 'accept - encoding': 'gzip, deflate',
  109. 'accept - language': 'zh - CN, zh;q = 0.9',
  110. 'cache - control': 'no - cache',
  111. 'Connection': 'keep-alive',
  112. 'csrf': 'HH3GHIQ0RYM',
  113. 'Referer': 'http://www.kuwo.cn/search/list?key=%E5%91%A8%E6%9D%B0%E4%BC%A6',
  114. 'User-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
  115. 'Chrome/99.0.4844.51 Safari/537.36',
  116. 'Cookie': '_ga=GA1.2.218753071.1648798611; _gid=GA1.2.144187149.1648798611; _gat=1; '
  117. 'Hm_lvt_cdb524f42f0ce19b169a8071123a4797=1648798611; '
  118. 'Hm_lpvt_cdb524f42f0ce19b169a8071123a4797=1648798611; kw_token=HH3GHIQ0RYM'
  119. }
  120. search_input = self.ui_url.get()
  121. if len(search_input) > 0:
  122. search_url = 'http://www.kuwo.cn/api/www/search/searchMusicBykeyWord?'
  123. search_data = {
  124. 'key': search_input,
  125. 'pn': '1',
  126. 'rn': '80',
  127. 'httpsStatus': '1',
  128. 'reqId': '858597c1-b18e-11ec-83e4-9d53d2ff08ff'
  129. }
  130. try:
  131. self.response_data = requests.get(search_url, params=search_data, headers=headers, timeout=20).json()
  132. songs_data = self.response_data['data']['list']
  133. if int(self.response_data['data']['total']) <= 0:
  134. mes_box.showerror(title='错误', message='搜索: {} 不存在.'.format(search_input))
  135. else:
  136. for i in range(len(songs_data)):
  137. self.show_result.insert('', i, values=(i + 1, songs_data[i]['artist'], songs_data[i]['name'],
  138. songs_data[i]['album']))
  139. except TimeoutError:
  140. mes_box.showerror(title='错误', message='搜索超时,请重新输入后再搜索!')
  141. else:
  142. mes_box.showerror(title='错误', message='未输入需查询的歌曲或歌手,请输入后搜索!')
  143. def get_song_url(self, event):
  144. """
  145. 获取下载歌曲的地址
  146. :return:
  147. """
  148. # treeview中的左键单击
  149. for item in self.show_result.selection():
  150. item_text = self.show_result.item(item, "values")
  151. # 获取
  152. self.song_num = int(item_text[0])
  153. # 获取下载歌曲的地址
  154. if self.song_num is not None:
  155. songs_data = self.response_data['data']['list']
  156. songs_req_id = self.response_data['reqId']
  157. song_rid = songs_data[self.song_num - 1]['rid']
  158. music_url = 'http://www.kuwo.cn/api/v1/www/music/playUrl?mid={}&type=convert_url3' \
  159. '&httpsStatus=1&reqId={}' \
  160. .format(song_rid, songs_req_id)
  161. response_data = requests.get(music_url).json()
  162. self.song_url = response_data['data'].get('url')
  163. self.song_name = songs_data[self.song_num - 1]['name']
  164. self.song_author = songs_data[self.song_num - 1]['artist']
  165. else:
  166. mes_box.showerror(title='错误', message='未选择要下载的歌曲,请选择')
  167. def download_music(self):
  168. """
  169. 下载音乐
  170. :return:
  171. """
  172. if not os.path.exists('./Download'):
  173. os.mkdir("./Download/")
  174. if self.song_num is not None:
  175. song_name = self.song_name + '--' + self.song_author + ".mp3"
  176. try:
  177. save_path = os.path.join('./3_Download/{}'.format(song_name)) \
  178. .replace('\\', '/')
  179. true_path = os.path.abspath(save_path)
  180. resp = requests.get(self.song_url)
  181. with open(save_path, 'wb') as file:
  182. file.write(resp.content)
  183. mes_box.showinfo(title='下载成功', message='歌曲:%s,保存地址为%s' % (self.song_name, true_path))
  184. except Exception:
  185. mes_box.showerror(title='错误', message='未找到存放歌曲的文件夹')
  186. else:
  187. mes_box.showerror(title='错误', message='未选择要下载的歌曲,请选择后下载')
  188. def progress_bar(self, file_size):
  189. """
  190. 任务加载进度条
  191. :return:
  192. """
  193. layout = [[sg.Text('任务完成进度')],
  194. [sg.ProgressBar(file_size, orientation='h', size=(40, 20), key='progressbar')],
  195. [sg.Cancel()]]
  196. # window只需将自定义的布局加载出来即可 第一个参数是窗口标题。
  197. window = sg.Window('机器人执行进度', layout)
  198. # 根据key值获取到进度条
  199. _progress_bar = window['progressbar']
  200. for i in range(file_size): # 循环
  201. event, values = window.read(timeout=10)
  202. if event == 'Cancel' or event is None:
  203. break
  204. _progress_bar.UpdateBar(i + 1)
  205. def ui_center(self):
  206. """
  207. UI界面窗口设置:居中
  208. """
  209. ws = self.ui_root.winfo_screenwidth()
  210. hs = self.ui_root.winfo_screenheight()
  211. x = int((ws / 2) - (self.ui_weight / 2))
  212. y = int((hs / 2) - (self.ui_height / 2))
  213. self.ui_root.geometry('{}x{}+{}+{}'.format(self.ui_weight, self.ui_height, x, y))
  214. def loop(self):
  215. """
  216. 函数说明:loop等待用户事件
  217. """
  218. self.ui_root.resizable(False, False) # 禁止修改窗口大小
  219. self.ui_center() # 窗口居中
  220. self.set_ui()
  221. self.ui_root.mainloop()
  222. if __name__ == '__main__':
  223. a = SetUI()
  224. a.loop()

运行效果

使用过程

菜单栏

打包的exe

 


总结

本文实现了一个VIP音乐解析系统,能够通过关键字检索需要的歌曲,并且设计了用户界面,可以进行直观的交互行为,也能将目标歌曲下载到本地同目录下的Download文件夹中。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/112122
推荐阅读
相关标签
  

闽ICP备14008679号