python实现可下载音乐的音乐播放器
本文实例为大家分享了tkinter+pygame+spider实现音乐播放器,供大家参考,具体内容如下
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()
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。