python如何实现可下载音乐的音乐播放器
小编给大家分享一下python如何实现可下载音乐的音乐播放器,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!
1.确定页面
SongSheet------ 显示歌单MusicCtrl ------显示音乐一些控件(播放,跳转,音量调节)SearchWindows ------搜索栏(搜索歌曲默认显示20条,可下载)
songSheet.py
#!/usr/bin/envpython #-*-coding:utf-8-*- #@Author:Minions #@Date:2019-11-2419:51:16 #@LastModifiedby:Minions #@LastModifiedtime:2019-12-1710:01:53 importtkinter importos fromtkinterimportttk importtime classSongSheet(tkinter.Frame): def__init__(self,master): self.frame=tkinter.Frame(master,height=230,width=300,bd=1, bg="SkyBlue") self.frame.place(x=0,y=0) self.filePath="C:\Musics" self.music=""#点击歌曲获得更新的路径 self.count=0#计数,共多少歌曲 defrun(self): #搜索按钮 searchBtn=tkinter.Button(self.frame,text="更新",bg="SkyBlue", command=self.showSheet,width=10, height=1) searchBtn.place(x=0,y=200) #显示歌单 defshowSheet(self): self.count=0 musics=os.listdir(self.filePath) tree=ttk.Treeview(self.frame) #定义列 tree["columns"]=("song") #设置列,列还不显示 tree.column("song",width=95) #设置表头和上面一一对应 tree.heading("song",text="song") #添加数据往第0行添加 formusicinmusics: #去除空格 music="".join(music.split("")) tree.insert("",0,text=self.count,values=(music)) self.count+=1 #鼠标选中一行回调 defselectTree(event): foritemintree.selection(): item_text=tree.item(item,"values") self.music="".join(item_text) #print(self.music) #选中行 tree.bind('<>',selectTree) tree.place(width=300,height=200,x=0,y=0) #添加滚动条 sy=tkinter.Scrollbar(tree) sy.pack(side=tkinter.RIGHT,fill=tkinter.Y) sy.config(command=tree.yview) tree.config(yscrollcommand=sy.set)
2.写出音乐控件
musicCtrl.py
#!/usr/bin/envpython #-*-coding:utf-8-*- #@Author:Minions #@Date:2019-11-2416:28:18 #@LastModifiedby:Minions #@LastModifiedtime:2019-12-1710:25:31 importtkinter fromtkinterimportttk importos importtime importpygame frommutagen.mp3importMP3 importrandom fromsongSheetimportSongSheet classMusicCtrl(object): def__init__(self,master): self.frame=tkinter.Frame(master,height=150,width=700,bd=1, bg="MediumSeaGreen") self.frame.place(height=150,width=700,x=0,y=250) self.nowPaly=True#是否正在播放音乐 self.filePath=r"C:\Musics"#从该文件夹读取 self.musicPath=""#用于拼接音乐的路径 self.songSheet=SongSheet(master) self.songSheet.run() self.music=os.path.join(self.filePath,self.musicPath)#音乐的路径 #整合功能 defrun(self): self.playMusic() self.refreshName() self.pauseMusic() self.volume() try: self.songPos() except: print("暂无歌曲载入!") #播放音乐按钮 defplayMusic(self): playBtn=tkinter.Button(self.frame,text="播放",command=self.playFunc, width=10,height=2) playBtn.place(x=300,y=10) #实现播放功能 defplayFunc(self): pygame.mixer.init() track=pygame.mixer.music.load(self.music)#载入一个音乐文件用于播放 pygame.mixer.music.play()#开始播放音乐流 #暂停播放按钮 defpauseMusic(self): pauseBtn=tkinter.Button(self.frame,text="暂停/继续", command=self.pauseFunc, width=10,height=2) pauseBtn.place(x=400,y=10) #暂停播放功能 defpauseFunc(self): #pygame.mixer.music.get_busy()#检测是否正在播放音乐 ifself.nowPaly: pygame.mixer.music.pause() self.nowPaly=False else: pygame.mixer.music.unpause()#恢复音乐播放 self.nowPaly=True #显示歌曲名称以及歌手 defshowName(self): songName=tkinter.Label(self.frame, fg="white",font=("华文行楷",10),bg="MediumSeaGreen", width=25,height=1) songName['text']=self.songSheet.music.split('.')[0] songName.place(x=35,y=15) self.music=os.path.join(self.filePath,self.songSheet.music) #更换音乐后应该继续播放,并且更换音乐时长 self.playFunc() self.songPos() #音量调节 defvolume(self): volumeNum=tkinter.Label(self.frame,text="volume",fg="Aquamarine", font=("华文行楷",10),bg="MediumSeaGreen", width=5,height=1) volumeNum.place(x=500,y=70) volume=tkinter.Scale(self.frame,from_=0,to=100, orient=tkinter.HORIZONTAL) volume.place(x=550,y=50) defshowNum(): pygame.mixer.music.set_volume(volume.get()*0.01)#参数值范围为0.0~1.0 tkinter.Button(self.frame,text="设置",command=showNum,bg="Aqua").place( x=550,y=100) #音乐绝对定位 defsongPos(self): #print(self.music.info.length) pos=tkinter.Scale(self.frame,from_=0,to=round( MP3(self.music).info.length), orient=tkinter.HORIZONTAL,tickinterval=50,length=300) pos.place(x=180,y=60) defshowNum(): #为了对一个MP3文件的进行绝对定位,建议首先调用rewind()函数,不然会一直往后走 pygame.mixer.music.rewind() ifpygame.mixer.music.get_busy(): self.curDuration=pos.get() pygame.mixer.music.set_pos(self.curDuration) else: print("请先播放音乐!") tkinter.Button(self.frame,text="设置",command=showNum,bg="Aqua").place( x=490,y=90) #点击歌单的歌更新名称 defrefreshName(self): refreshNameBtn=tkinter.Button(self.frame,text="update",command=self.showName, width=10,height=2) refreshNameBtn.place(x=45,y=50)
3.核心爬取音乐
music.py
#-*-coding:utf-8-*- importrequests,hashlib,sys,click,re,base64,binascii,json,os fromCryptodome.CipherimportAES fromhttpimportcookiejar classEncrypyed(): """ 解密算法 """ def__init__(self): self.modulus='00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7' self.nonce='0CoJUm6Qyw8W8jud' self.pub_key='010001' #登录加密算法,基于https://github.com/stkevintan/nw_musicbox脚本实现 defencrypted_request(self,text): text=json.dumps(text) sec_key=self.create_secret_key(16) enc_text=self.aes_encrypt(self.aes_encrypt(text,self.nonce),sec_key.decode('utf-8')) enc_sec_key=self.rsa_encrpt(sec_key,self.pub_key,self.modulus) data={'params':enc_text,'encSecKey':enc_sec_key} returndata defaes_encrypt(self,text,secKey): pad=16-len(text)%16 text=text+chr(pad)*pad encryptor=AES.new(secKey.encode('utf-8'),AES.MODE_CBC,b'0102030405060708') ciphertext=encryptor.encrypt(text.encode('utf-8')) ciphertext=base64.b64encode(ciphertext).decode('utf-8') returnciphertext defrsa_encrpt(self,text,pubKey,modulus): text=text[::-1] rs=pow(int(binascii.hexlify(text),16),int(pubKey,16),int(modulus,16)) returnformat(rs,'x').zfill(256) defcreate_secret_key(self,size): returnbinascii.hexlify(os.urandom(size))[:16] classSong(): """ 歌曲对象,用于存储歌曲的信息 """ def__init__(self,song_id,song_name,song_num,picUrl,singer_name, song_url=None): self.song_id=song_id self.song_name=song_name self.song_num=song_num self.singer_name=singer_name self.picUrl=picUrl self.song_url=''ifsong_urlisNoneelsesong_url classCrawler(): """ 网易云爬取API """ def__init__(self,timeout=60,cookie_path='.'): self.headers={ '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.com', 'Referer':'http://music.163.com/search/', 'User-Agent':'Mozilla/5.0(WindowsNT10.0;WOW64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/63.0.3239.132Safari/537.36' } self.session=requests.Session() self.session.headers.update(self.headers) self.session.cookies=cookiejar.LWPCookieJar(cookie_path) self.download_session=requests.Session() self.timeout=timeout self.ep=Encrypyed() self.result=[] defpost_request(self,url,params): """ Post请求 :return:字典 """ data=self.ep.encrypted_request(params) resp=self.session.post(url,data=data,timeout=self.timeout) result=resp.json() ifresult['code']!=200: click.echo('post_requesterror') else: returnresult defsearch(self,search_content,search_type,limit=9): """ 搜索API :paramssearch_content:搜索内容 :paramssearch_type:搜索类型 :paramslimit:返回结果数量 :return:字典. """ url='http://music.163.com/weapi/cloudsearch/get/web?csrf_token=' params={'s':search_content,'type':search_type,'offset':0,'sub':'false','limit':limit} result=self.post_request(url,params) #print(result['result']['songs'][3]['ar'][0]['name']) returnresult defsearch_song(self,song_name,song_num,quiet=True,limit=20): """ 根据音乐名搜索 :paramssong_name:音乐名 :paramssong_num:下载的歌曲数 :paramsquiet:自动选择匹配最优结果 :paramslimit:返回结果数量 :return:Song独享 """ result=self.search(song_name,search_type=1,limit=limit) ifresult['result']['songCount']<=0: click.echo('Song{}notexisted.'.format(song_name)) else: songs=result['result']['songs'] ifquiet: self.result=[]#更新result forsonginsongs: singers=[] #""" picUrl=song['al']['picUrl'] #""" fornameinsong['ar']: singers.append(name['name']) song_id,song_name=song['id'],song['name'] singer_name="_".join(singers) song=Song(song_id=song_id,song_name=song_name, song_num=song_num,singer_name=singer_name,picUrl=picUrl) self.result.append(song) picUrl=songs[0]['al']['picUrl'] #""" song_id,song_name=songs[0]['id'],songs[0]['name'] song=Song(song_id=song_id,song_name=song_name, song_num=song_num,singer_name=self.result[0].singer_name, picUrl=picUrl) returnsong defget_song_url(self,song_id,bit_rate=320000): """ 获得歌曲的下载地址 :paramssong_id:音乐ID. :paramsbit_rate:{'MD128k':128000,'HD320k':320000} :return:歌曲下载地址 """ url='http://music.163.com/weapi/song/enhance/player/url?csrf_token=' csrf='' params={'ids':[song_id],'br':bit_rate,'csrf_token':csrf} result=self.post_request(url,params) #歌曲下载地址 song_url=result['data'][0]['url'] #歌曲不存在 ifsong_urlisNone: click.echo('Song{}isnotavailableduetocopyrightissue.'.format(song_id)) else: returnsong_url defget_song_by_url(self,song_url,song_name,song_num,singer_name, folder): """ 下载歌曲到本地 :paramssong_url:歌曲下载地址 :paramssong_name:歌曲名字 :paramssong_num:下载的歌曲数 :paramsfolder:保存路径 """ #forresinself.result: #print(res.song_name,res.song_id,res.singer_name) #print("--------") #print(song_url,song_name,singer_name) classNetease(): """ 网易云音乐下载 """ def__init__(self,timeout,folder,quiet,cookie_path): self.crawler=Crawler(timeout,cookie_path) self.folder='.'iffolderisNoneelsefolder self.quiet=quiet self.url='' self.pic='' defdownload_song_by_search(self,song_name): """ 根据歌曲名进行搜索 :paramssong_name:歌曲名字 :paramssong_num:下载的歌曲数 """ try: song=self.crawler.search_song(song_name,self.quiet) except: click.echo('download_song_by_seracherror') #如果找到了音乐,则下载 ifsong!=None: self.download_song_by_id(song.song_id,song.song_name, song.song_num,song.singer_name,self.folder) self.pic=song.picUrl defdownload_song_by_id(self,song_id,song_name,song_num,singer_name, folder='.'): """ 通过歌曲的ID下载 :paramssong_id:歌曲ID :paramssong_name:歌曲名 :paramssong_num:下载的歌曲数 :paramsfolder:保存地址 """ try: url=self.crawler.get_song_url(song_id) #去掉非法字符 song_name=song_name.replace('/','') song_name=song_name.replace('.','') self.crawler.get_song_by_url(url,song_name,song_num, singer_name,folder) except: click.echo('download_song_by_iderror')
4.将爬取音乐搜索栏整合
searchWindows.py
#!/usr/bin/envpython #-*-coding:utf-8-*- #@Author:Minions #@Date:2019-11-2510:31:56 #@LastModifiedby:Minions #@LastModifiedtime:2019-12-1712:40:31 importtkinter fromtkinterimportttk importos fromurllibimportrequest frommusicimportNetease,Crawler importrequests classSearchWindows(tkinter.Frame): def__init__(self,master): self.frame=tkinter.Frame(master,height=240,width=500,bd=1, bg="Purple") self.songs=None#搜索到的所有歌曲(20)的信息 self.frame.place(x=300,y=0) self.info=None#当前歌曲的信息 self.fileName="C:\Musics\\" timeout=60 output='Musics' quiet=True cookie_path='Cookie' self.netease=Netease(timeout,output,quiet,cookie_path) defrun(self): self.searchBar() self.download() #搜索框 defsearchBar(self): entry=tkinter.Entry(self.frame) entry.place(width=200,height=30,x=50,y=10) defgetValue(): self.netease.download_song_by_search(entry.get()) self.songs=self.netease.crawler.result self.showSong() searchBtn=tkinter.Button(self.frame,text="搜索",bg="DarkOrchid", command=getValue,width=10,height=1) searchBtn.place(x=270,y=10) #显示搜索到的歌曲 defshowSong(self): tree=ttk.Treeview(self.frame) #定义列 tree["columns"]=("song","singer","url") #设置列,列还不显示 tree.column("song",width=50) tree.column("singer",width=50) tree.column("url",width=50) #设置表头和上面一一对应 tree.heading("song",text="song") tree.heading("singer",text="singer") tree.heading("url",text="url") count=len(self.songs) forsonginreversed(self.songs): url=self.netease.crawler.get_song_url(song.song_id) tree.insert("",0,text=count,values=(song.song_name, song.singer_name,url)) count-=1 #鼠标选中一行回调 defselectTree(event): foritemintree.selection(): item_text=tree.item(item,"values") self.info=item_text #滚动条 sy=tkinter.Scrollbar(tree) sy.pack(side=tkinter.RIGHT,fill=tkinter.Y) sy.config(command=tree.yview) tree.config(yscrollcommand=sy.set) #选中行 tree.bind('<>',selectTree) tree.place(width=300,height=200,x=50,y=50) #下载选中的歌曲 defdownload(self): defdownloadSong(): ifself.infoisNone: print("该歌曲下载失败") else: request.urlretrieve(self.info[2], self.fileName+self.info[1]+'-'+self.info[0]+'.mp3') print("%s-%s下载成功"%(self.info[1],self.info[0])) #下载按钮 downloadBtn=tkinter.Button(self.frame,text="下载",bg="DarkOrchid", command=downloadSong,width=6,height=1) downloadBtn.place(x=345,y=200)
5.整合所有部分
main.py
#!/usr/bin/envpython #-*-coding:utf-8-*- #@Author:Minions #@Date:2019-11-2420:10:15 #@LastModifiedby:Minions #@LastModifiedtime:2019-12-179:55:31 importtkinter fromsearchWindowsimportSearchWindows frommusicCtrlimportMusicCtrl fromsongSheetimportSongSheet importos win=tkinter.Tk() win.title("Minions音乐播放器") win.geometry("700x400") ifos.path.exists("C:/Musics"): print("xxx") else: os.mkdir("C:/Musics") searchWin=SearchWindows(win) searchWin.run() songSheetWin=SongSheet(win) songSheetWin.run() musicWin=MusicCtrl(win) musicWin.run() win.mainloop()
以上是“python如何实现可下载音乐的音乐播放器”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注恰卡编程网行业资讯频道!
推荐阅读
-
Python多线程抓取代理服务器
Python作为一门功能强大的脚本语言来说,经常被用来写爬虫程序,下面是Python爬虫多线程抓取代理服务器。年前是用//lin...
-
Python中怎么动态声明变量赋值
这篇文章将为大家详细讲解有关Python中怎么动态声明变量赋值,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文...
-
python中变量的存储原理是什么
本篇文章给大家分享的是有关python中变量的存储原理是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有...
-
Python中怎么引用传递变量赋值
这篇文章将为大家详细讲解有关Python中怎么引用传递变量赋值,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文...
-
python中怎么获取程序执行文件路径
python中怎么获取程序执行文件路径,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的...
-
Python中如何获取文件系统的使用率
Python中如何获取文件系统的使用率,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴...
-
Python中怎么获取文件的创建和修改时间
这篇文章将为大家详细讲解有关Python中怎么获取文件的创建和修改时间,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读...
-
python中怎么获取依赖包
今天就跟大家聊聊有关python中怎么获取依赖包,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据...
-
python怎么实现批量文件加密功能
这篇文章主要介绍“python怎么实现批量文件加密功能”,在日常操作中,相信很多人在python怎么实现批量文件加密功能问题上存在...
-
python中怎么实现threading线程同步
小编给大家分享一下python中怎么实现threading线程同步,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!...