爬虫实战---爬取音乐
爬虫实战---爬取音乐
前言:
此方法来源于网络:https://www.bilibili.com/video/BV1g8411G7ZC?p=1, 仅供个人学习
模块:
模块 |
---|
os |
tkinter |
webbrowser |
requests |
PySimpleGUI |
retrying |
from tkinter import ttk |
import tkinter.messagebox |
每个模块功能介绍:
1.os模块:
1.简介:os 模块是 Python 内置的与操作系统中的文件系统相关的模块,该模块依赖于操作系统。通常情况下,如不特别指出,该模块提供的方法、属性在Windows 和 UNIX(Linux 和Mac OS X) 系统上都是可用的。dir(os)即可获取所有方法列表
2.常用方法:
-
os.getcwd() : 获取当前工作目录的路径,在 Python 中,指定文件路径时需要对路径分隔符
\
进行转义,即将路径中的\
替换为\\
。注:在指定文件路径时,也可以在表示路径的字符串前面加上字母r(R)
,那么该字符串将原样输出,这时路径中的分隔符就不需要再转义了。path = os.getcwd -
**os.path() ** :
- os.path.abspath() : 获取当前工作文件的绝对路径
- os.path.basename() : 获取文件名,不包含目录部分, 如果该路径本身就是个目录,那么返回的就是空
- os.path.dirname() : 获取文件的目录部分, dirname + basename 就可以构成文件的完整路径名
- os.path.exists() : 判断路径是否存在,这里的路径包括目录和文件。
- os.path.getsize() : 获取文件大小,也可以获取目录(所有文件的)大小,取决你你传的路径参数是文件还是目录。单位是字节
- os.path.split() : split 方法会将路径切割成两部分,以最后一个斜杠作为切割点,第一部分是文件所在的目录, 第二部分文件名 本身。
- os.path.join() : oin是与split对应的方法,用于拼接文件路径。
- os.path.isfile() : 判断路径是否为文件,如果该文件不存在也不会报错,而是直接返回False
-
**os.listdir() **: 返回指定路径下的目录名和文件名(不包括子孙目录) ,是一个列表,输出结果列表是以字母顺序排列,不区分文件和目录。
- 参数:
- path:表示一个路径,不能是文件路径。
- 参数:
-
os.makedirs():采用递归方法创建多级目录
- 参数:
- name:用于指定要创建目录的路径
- mode:指定目录的模式,默认模式为八进制的 777。
- exist_ok:可选参数,如果值为 False,当要创建的目录已经存在时,抛出 FileExistsError 异常;如果值为True,当要创建的目录已经存在时,不会抛出异常。默认值为 False。
- 返回值:无。
os.makedirs(r'xi\xixi\xixixi') //将创建三级目录,xi为一级 - 参数:
-
os.removedirs():递归删除目录
- 参数:
- name:用于指定要删除目录的路径。该目录中,最后一级目录必须为空,否则将抛出
OSError:[WinError 145] 目录不是空的
异常。 - 无返回值
- name:用于指定要删除目录的路径。该目录中,最后一级目录必须为空,否则将抛出
- 参数:
-
os.rmdir():删除空目录
- 参数:
- path:表示要删除的目录,可以使用相对路径,也可以使用绝对路径。
- dir_fd :可选参数,用于指定要删除目录的相对于目录描述符的路径,而不是遵循符号链接(软链接)。
- 返回值:无。
-
rename():重命名文件或目录,在方法中,如果出现
\*
则表示其后面的参数为命名关键字参数,这是一个特殊的分隔符。在调用时,命名关键字参数必须传入参数名。- 参数:
- src :表示字符串类型的路径,用于指定需要进行重命名的文件或目录的路径。
- dst:表示字符串类型的路径,用于指定新的文件或目录名称。如果指定的路径已经存在,则多数系统下将抛FileExistsError 异常。
- src_dir_fd :可选参数,用于指定源地址的相对于目录描述符的路径,而不是遵循符号链接(软链接)。
- dst_dir_fd :可选参数,用于指定目标地址的相对于目录描述符的路径,而不是遵循符号链接(软链接)。
- 返回值:无
- 参数:
参考自https://blog.csdn.net/xw1680/article/details/125563034,更多方法详见。
2.tkinter模块:
参考1:https://blog.csdn.net/xw1680/article/details/118088846?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167730993416800182718786%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=167730993416800182718786&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_ecpm_v1~rank_v31_ecpm-1-118088846-null-null.blog_rank_default&utm_term=tkinter&spm=1018.2226.3001.4450
参考2:https://blog.csdn.net/SGDBS233/article/details/125113252
3.webbrowser模块:
参考:https://www.bookstack.cn/read/python-3.10.0-zh/632b2333e26cd2d3.md#id1
4.requests模块:
参考:https://www.runoob.com/python3/python-requests.html
https://www.cnblogs.com/simono/p/16629306.html
5.PySimpleGUI模块:
参考:https://blog.csdn.net/W295723987/article/details/126611877
https://www.cnblogs.com/L707/p/16340905.html
6.retrying模块:
参考:http://www.manongjc.com/detail/39-wkiwvutawajzimj.html
7.tkinter子模块ttk:
参考:https://blog.csdn.net/pythonitstream/article/details/124358774 (上)
https://blog.csdn.net/pythonitstream/article/details/124508042 (下)
8.tkinter子模块messagebox
参考:https://www.jb51.net/article/216076.htm
https://blog.csdn.net/qq_34745941/article/details/116995050
代码:
import os #关于操作系统的一个python标准库 import tkinter as tk #gui图形界面化模块 import webbrowser #提供了一个高级接口,允许向用户显示基于Web的文档。 import requests import tkinter.messagebox as mes_box import PySimpleGUI as sg from tkinter import ttk from retrying import retry #对同一个操作进行多次尝试 class SetUI(object): """ 音乐弹框界面 """ def __init__(self,weight=1000,height=600): self.ui_weight=weight self.ui_height=height self.title="音乐破解软件" self.ui_root=tk.Tk(className=self.title) #建立主窗口并设置窗口名 self.ui_url = tk.StringVar() #StringVar()跟踪变量值的变化,把最新的值显示到界面上 self.ui_var = tk.IntVar()#记录数值.get()获取值, .set()设置值 self.ui_var.set(1)#1为选中,0未选中 self.show_result = None self.song_num = None self.response_data = None self.song_url = None self.song_name = None self.song_author = None def set_ui(self): """ 设置简易ui界面 :return: """ #Frame空间 frame_1 = tk.Frame(self.ui_root)#可作为其他组件的容器,常用来对组件进行分组Label 标 签,常用来显示单行文本 frame_2 = tk.Frame(self.ui_root) frame_3 = tk.Frame(self.ui_root) frame_4 = tk.Frame(self.ui_root) #ui界面中菜单设计 ui_menu = tk.Menu(self.ui_root) #创建菜单栏 #显示菜单 self.ui_root.config(menu=ui_menu) #创建子菜单 file_menu = tk.Menu(ui_menu,tearoff = 0)#Tearoff 默认情况下(tearoff=1 或 True)显示“撕掉元素(‘------------’) ui_menu.add_cascade(label='菜单',menu = file_menu)#添加子菜单,设置子菜单名称 #添加子菜单选项触发单元,command设置触发事件 file_menu.add_command(label='使用说明',command=lambda:webbrowser.open('www.baidu.com')) file_menu.add_command(label='关于作者',command=lambda:webbrowser.open('www.baidu.com')) file_menu.add_command(label='退出',command=self.ui_root.quit)#退出程序 #控件内容设置 choice_passageway = tk.Label(frame_1,text = '请选择音乐搜索通道',padx=10,pady=10) #Label:标签组件。主要用 #于显示文本,添加提示信息等。 passageway_button1 = tk.Radiobutton(frame_1,text='酷我', variable=self.ui_var,value=1, width=10,height=3)#单选 passageway_button2 = tk.Radiobutton(frame_1, text='网易云', variable=self.ui_var, value=2, width=10, height=3) passageway_button3 = tk.Radiobutton(frame_1, text='QQ音乐', variable=self.ui_var, value=3, width=10, height=3) passageway_button4 = tk.Radiobutton(frame_1, text='酷狗', variable=self.ui_var, value=4, width=10, height=3) input_link = tk.Label(frame_2,text="请输入歌曲名或歌手") #文本框Entry用于接收输入的数据。文本框Entry的基本格式为:txt = tkinter.Entry(容器名称,width=宽度,文字字体、颜色等) entry_style = tk.Entry(frame_2,textvariable=self.ui_url,highlightcolor='Fuchsia', highlightthickness=1,width=35) label2 = tk.Label(frame_2,text=" ") play_button = tk.Button(frame_2,text='搜索',font=('楷体',11),fg='Purple',width=2,height=1, command=self.get_KuWoMusic) label3= tk.Label(frame_2,text=" ") #表格样式 columns=("序号","歌手","歌曲","专辑") #设置表格,headings表示显示在顶部,colums是要显示的数据 self.show_result = ttk.Treeview(frame_3,height=20,show="headings",columns= columns) #下载 download_button = tk.Button(frame_4,text="下载",font=('楷体',11),fg='Purple',width=6, height=1,padx=5,pady=5,command=self.download_music) #控件布局 frame_1.pack() frame_2.pack() frame_3.pack() frame_4.pack() choice_passageway.grid(row=0,column=0) passageway_button1.grid(row=0,column=1) passageway_button2.grid(row=0,column=2) passageway_button3.grid(row=0,column=3) passageway_button4.grid(row=0,column=4) input_link.grid(row=0,column=0) entry_style.grid(row=0,column=0) label2.grid(row=0,column=2) play_button.grid(row=0,column=3,ipadx=10,ipady=10) label3.grid(row=0,column=4) self.show_result.grid(row=0,column=4) download_button.grid(row=0,column=4) #设置表头 self.show_result.heading("序号",text="序号") self.show_result.heading("歌曲",text="歌曲") self.show_result.heading("歌手",text="歌手") self.show_result.heading("专辑",text="专辑") #设置列 self.show_result.column("序号",width=100,anchor='center') self.show_result.column("歌曲",width=200,anchor='center') self.show_result.column("歌手",width=300,anchor='center') self.show_result.column("专辑",width=400,anchor='center') #鼠标点击 self.show_result.bind('<ButtonRelease-1>',self.get_song_url)#1代表左键,n为2代表中键,n为3代表右键 @retry(stop_max_attempt_number=5)#停止最大尝试次数 def get_KuWoMusic(self): """ 获取QQ音乐 :return: """ #清空treeview表格数据 for item in self.show_result.get_children():#get_children()函数,其返回的是treeview中的记录号. self.show_result.delete(item) headers = { # 传入必要请求头,反爬-------------------------------------------------------- "Accept": "application/json, text/plain, */*", "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "keep-alive", "Cookie": "_ga=GA1.2.2058800930.1642474837; _gid=GA1.2.1174281146.1642474837; Hm_lvt_cdb524f42f0ce19b169a8071123a4797=1642490265,1642490289,1642490402,1642498818; Hm_lpvt_cdb524f42f0ce19b169a8071123a4797=1642499234; kw_token=YK4UZW2UPL", "csrf": "YK4UZW2UPL", "Host": "www.kuwo.cn", "Referer": "http://www.kuwo.cn/", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36", } search_input = self.ui_url.get()#得到用户输入内容 if len(search_input) >0: search_url = 'http://www.kuwo.cn/api/www/search/searchMusicBykeyWord?' """key携带的值,是我们要搜索的值;pn,按照常量,我们猜测,其为页数;rn,我们猜测其为一页显示的数量""" search_data = { 'key':search_input, 'pn':'1', 'rn': '80', 'httpsStatus':'1', 'reqId':'858597c1-b18e-11ec-83e4-9d53d2ff08ff' } try:# params 接收一个字典或者字符串的查询参数,字典类型自动转换为url编码,不需要urlencode() self.response_data = requests.get(search_url,params=search_data,headers=headers, timeout=20).json() songs_data = self.response_data['data']['list'] if int(self.response_data['data']['total'])<=0: mes_box.showerror(title='错误',message='搜索:{} 不存在.'.format(search_input)) else: for i in range(len(songs_data)): self.show_result.insert('',i,values=(i+1,songs_data[i]['artist'], songs_data[i]['name'], songs_data[i]['album'])) """insert(parent, index, iid=None, **kw) 解释: parent : 对于有树栏的Treeview,parent是父节点,对于只是列表栏的Treeview,parent一般为空。 index :插入位置。可以是END或’end’ ,也可以是数字的,如果你想新插入的item(记录)成为第某节点的第一 个,index就设为0,以此类推。 iid : 每一行记录(item)的标识符,这个参数,我上面没有讲解,等下,我会专门讲解。 **kw :设置插入的记录(item)所支持属性,""" except TimeoutError: mes_box.showerror(title='错误',message='搜索超时,请重新输入再搜索!') else: mes_box.showerror(title='错误',message='未输入需查询的歌曲或歌手,请输入后搜索!') def get_song_url(self ,event): """ 获取下载歌曲的地址 :param event: :return: """ #treeview中的单击左键 for item in self.show_result.selection():#取的选项,要下载的歌曲 item_text = self.show_result.item(item,"value")#item获得字典· #获取 self.song_num=int(item_text[0]) #获取下载歌曲的地址 if self.song_num is not None: songs_data = self.response_data['data']['list'] songs_req_id = self.response_data['reqId'] songs_rid = songs_data[self.song_num-1]['rid'] music_url = 'http://www.kuwo.cn/api/v1/www/music/playUrl?mid={}&type=convert_url3'\ '&httpsStatus=1&reqId={}'.format(songs_rid,songs_req_id) response_data = requests.get(music_url).json() self.song_url = response_data['data'].get('url') self.song_name = songs_data[self.song_num-1]['name'] self.song_author = songs_data[self.song_num-1]['artist'] else: mes_box.showerror(title='错误',message='未选择要下载的歌曲,请选择') def download_music(self): """ 下载音乐 :return: """ self.progress_bar(100) if not os.path.exists('./music'): os.mkdir("./music/") if self.song_num is not None: song_name = self.song_name+'--'+self.song_author+".mp3" try: save_path = os.path.join('./music/{}'.format(song_name))\ .replace('\\','/') true_path = os.path.abspath(save_path) resp= requests.get(self.song_url) with open(save_path,'wb') as file: file.write(resp.content) mes_box.showinfo(title='下载成功',message='歌曲:%s,保存地址为%s'%(self.song_name, true_path)) except Exception: mes_box.showerror(title='错误',message='未找到存放歌曲的文件夹') else: mes_box.showerror(title='错误',message='未选择要下载的歌曲,请选择后下载') def progress_bar(self,file_size): """ 任务加载进度条 :param file_size: :return: """ #orientation 表示 进度条是横向的或是纵向的。h横向 v纵向(默认) #size是窗口尺寸 layout = [[sg.Text('任务完成进度')], [sg.ProgressBar(file_size,orientation='h',size=(40,20),key='progressbar')], [sg.Cancel()]]#取消按钮 #window只需将自定义的布局加载出来即可,第一个参数是窗口标题 window=sg.Window('机器人执行进度',layout) #根据key值获取到进度条 _progress_bar = window['progressbar'] for i in range(file_size):# read读取窗口,返回两个值,一个是事件,一个是值 event,value = window.read(timeout=10) if event == 'Cancel' or event is None: break _progress_bar.UpdateBar(i+1)#更新进度条 def ui_center(self): """ UI界面窗口设置:居中 :return: """ ws=self.ui_root.winfo_screenwidth()#获取电脑屏幕的 hs=self.ui_root.winfo_screenheight() x=int((ws/2)-(self.ui_weight/2)) y=int((hs/2)-(self.ui_height/2)) self.ui_root.geometry('{}x{}+{}+{}'.format(self.ui_weight,self.ui_height,x,y)) #geometry设定主窗口的大小以及位置,当参数值为 None 时表示获取窗口的大小和位置信息。 def loop(self): """ 函数说明:loop等待用户事件 :return: """ self.ui_root.resizable(False,False) #禁止修改窗口大小 self.ui_center() #窗口居中 self.set_ui() self.ui_root.mainloop() #进入等待与处理窗口事件 if __name__=='__main__': a=SetUI()#定义一个实例 a.loop()#调用函数
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)