wxpython+pygame+playwright实现本地音乐播放器及歌词自动爬虫下载播放

本文介绍了一个使用wxPython、playwright自动化框架和pygame库开发的音乐播放器,支持多种播放模式,能自动搜索和下载歌词。代码示例展示了如何实现音乐列表管理、播放控制和歌词同步功能。
摘要由CSDN通过智能技术生成

直接上代码:

# -*- coding: utf-8 -*-

import pygame,os,sys,random,wx,re,asyncio

from mutagen.mp3 import MP3

import wx.lib.agw.aui as aui

from playwright.async_api import async_playwright


 

class panel1(wx.Panel):#初始化面板

    def __init__(self,parent):

        wx.Panel.__init__(self,parent,id=wx.ID_ANY,pos=wx.DefaultPosition,size=(700,400))

        pygame.init()

        pygame.mixer.init()

        self.playing = False      

        self.index = 0      #初始化播放歌曲索引

        self.music = None   #初始化播放歌曲

        self.dic = {}    #初始化歌曲字典

        self.click = 0  #初始化播放模式

        self.dura = 0    #初始化歌曲时长

        self._init_ui()   #初始化界面

       

    def _init_ui(self):

        self.list=wx.ListCtrl(self,-1,(0,25),(200,300),wx.LC_REPORT,name=u'音乐列表')

        self.st=wx.StaticText(self ,1 ,u'请先导入音乐列表')

        self.tc = wx.TextCtrl(self, -1,u'F:\music')

        self.tc.SetForegroundColour('blue')

        self.playbutton = wx.Button(self , 102 , u'播放')#初始化播放/暂停按钮

        self.modebutton = wx.Button(self , 104 , u'顺序播放')#初始化播放模式

        hbox = wx.BoxSizer(wx.HORIZONTAL)

        lhbox = wx.BoxSizer(wx.HORIZONTAL)#左边横向BOX

        rhbox = wx.BoxSizer(wx.HORIZONTAL)

        vbox0 = wx.BoxSizer(wx.VERTICAL) #第一列

        vbox1 = wx.BoxSizer(wx.VERTICAL)

       

        hbox.Add(vbox0)

        hbox.Add(vbox1)

       

        vbox0.Add(self.list)

        vbox0.Add(self.st)

        vbox0.Add(lhbox)

        vbox1.Add(rhbox)

        lhbox.Add(self.tc)

        lhbox.Add(wx.Button(self, 100, u'导入'), 1, 10)

       

        rhbox.Add(wx.Button(self , 101 , u'上一曲') , 1 , wx.ALL, 5)

        rhbox.Add(self.playbutton , 102 , wx.ALL, 5)

        rhbox.Add(wx.Button(self , 103 , u'下一曲'),  1 , wx.ALL, 5)

        rhbox.Add(self.modebutton , 1 , wx.ALL, 5)

        self.slider = wx.Slider(self,-1,50,0,100)

        rhbox.Add(self.slider, 1, wx.ALL, 5)

        self.progress = wx.Gauge(self,pos=wx.DefaultPosition, size=wx.Size( 450,2), style=wx.GA_HORIZONTAL)

        vbox1.Add(self.progress,1, wx.ALL, 5)

        self.sst = wx.StaticText(self ,1 ,u'当前未播放')

        vbox1.Add(self.sst,1, wx.ALL, 5)

        self.lyc = wx.StaticText(self ,wx.ID_ANY ,u'', wx.DefaultPosition, wx.Size( 450,30))

        self.lyc.SetFont( wx.Font( 18, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "楷体" ) )

        self.lyc.SetForegroundColour('BLUE' )

        vbox1.Add(self.lyc,0, wx.EXPAND|wx.ALL, 5)

        self.lyc2 = wx.StaticText(self ,wx.ID_ANY ,u'\t', wx.DefaultPosition, wx.Size( 450,60))

        self.lyc2.SetFont( wx.Font( 18, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "楷体" ) )

        # self.lyc2.SetForegroundColour( wx.Colour(255 ,102,204 ) )

        self.lyc2.SetForegroundColour('green' )

        vbox1.Add(self.lyc2,0, wx.EXPAND|wx.ALL, 5)

        self.SetSizer(hbox)

        self.Layout()

        self.Bind(wx.EVT_BUTTON, self.btn_handler)

        self.slider.Bind(wx.EVT_SLIDER,self.change_volume)

    def CreatListctrl(self,dic):     #播放列表

        #播放列表

        self.list.ClearAll()

        self.list.InsertColumn(0,u'序号',width=25)

        self.list.InsertColumn(1,u'音乐',width=130)

        self.list.InsertColumn(2,u'时长',width=50)

        for key in  dic.keys():

           index = self.list.InsertItem(key,str(key+1))

           self.list.SetItem(index,1,dic[key][1])

           self.list.SetItem(index,2,str(dic[key][2]))

        self.list.Bind(wx.EVT_LIST_ITEM_SELECTED,self.Checkclick)

        self.list.Bind(wx.EVT_LIST_ITEM_ACTIVATED,self.DoubleClick)

    def DoubleClick(self, evt):#双击或者回车事件:播放

        index = evt.GetIndex()

        self.playing = False

        pygame.mixer.music.stop()

        self.player(index)

    def player(self,index):     #播放音乐

        pygame.mixer.music.load(self.getmusic(index))       # 加载音乐

        pygame.mixer.music.set_endevent(pygame.USEREVENT)   # 设置结束事件

        pygame.mixer.music.play(0)  # 开始播放音乐

        self.music = self.getmusicname(index)       # 获取音乐名称

        dura = self.dic[index][2]   # 获取音乐时长

        self.progress.SetRange(dura)

        self.sst.Label = u'当前正在播放:%s'%self.music  # 显示当前播放音乐

        self.sst.Update()   # 更新显示

        print('正在播放:',self.music)  # 打印当前播放音乐

        self.playbutton.Label = u'暂停' # 显示暂停按钮

        self.playing = True

        self.loadlyc()

        while self.playing:

            self.dr = pygame.mixer.music.get_pos()

            self.progress.SetValue(self.dr)

            self.lycplayer(self.dr)          

            for event in pygame.event.get():    # 监听事件

                if event.type == pygame.QUIT:

                    self.playing = False

                    print('退出')

                    pygame.quit()

                    sys.exit()

                if event.type == pygame.USEREVENT:  # 监听用户事件

                    index = self.playmode(self.click)   # 点击播放模式

                    self.player(index)  # 点击播放模式

    def getmusic(self,index): #索引到音乐文件

     #   music = self.dic[index][0] + '\\' + self.dic[index][1]

        return os.path.join(self.dic[index][0],self.dic[index][1])

    def getmusicname(self,index):   #索引到音乐名称

        return self.dic[index][1]    

   

    async def downloadlyc(self,msg):    #Playwright自动化框架下载歌词

        print('search lyric')

        async with async_playwright() as playwright:

            browser = await playwright.chromium.launch(headless=True)

            context = await browser.new_context()

            page = await context.new_page()

            await page.goto("https://www.musicenc.com/")

            await page.locator('#searchInput').fill(msg)

            await page.get_by_role("button", name="🔍").click()

            results= await page.locator(".list > li > a ").all_inner_texts()

            for result in results:

                if re.search(result,msg):

                    text = result

                    break

                else :

                    text = msg

                    continue

            async with page.expect_popup() as page_info:

                await page.locator(".list > li > a ").filter(has_text=text).first.click()

            print('Found lyric')

            page2 = await page_info.value

            # await page2.wait_for_load_state('load')

            async with page2.expect_download() as download_info:

                await page2.get_by_role("button", name="LyricsDownload").click()

                download = await download_info.value

                name = msg+'.txt'

                path = self.tc.Value

                await download.save_as(os.path.join(path,name))

                print(f'download{name}')

    def loadlyc(self):    #加载歌词

        lycdic ={}

        lyclist = []

        lycname = self.music.split('.m')[0]

        lycpath = os.path.join(self.tc.Value,lycname+'.txt')

        if os.path.exists(lycpath.strip()):

            with open(lycpath,'r',encoding='utf-8') as f:

                lyc = f.readlines()

            for j in range(len(lyc)):

                lyric_data = re.findall(r'(\d{2}:\d{2}).*?](.+)',lyc[j])

                for i in lyric_data:

                    times = (int(i[0].split(':')[0])*60 + round(float(i[0].split(':')[1]),3))*1000

                    lycdic[times] = i[1]

                    lyclist.append(times)

        else:

            try :

                asyncio.run(self.downloadlyc(lycname))  #下载歌词

            except Exception as e :

                print(e)

            finally:

                self.loadlyc()   #加载歌词

        return lycdic,lyclist

    def lycplayer(self,dr):      #播放歌词

        lycdic,lyclist = self.loadlyc()

        for i in range(len(lyclist)-1):

            if dr >= lyclist[i] and dr < lyclist[i+1]:

                if i % 2 == 0 :

                    self.lyc.Label = lycdic[lyclist[i]]

                    self.lyc.Update()

                    self.lyc2.SetLabelText ('\t'+lycdic[lyclist[i+1]])

                    self.lyc2.Update()

           

    def findmusic(self,path):   #本地查找音乐文件

        songs = []

        for file in os.listdir(path):

            childpath = os.path.join(file)

            if file.endswith(('.mp3','m4a','.wav','ogg','wma')): #判断是否音乐文件

                song = MP3(os.path.join(path ,file))

                duration = int(round(song.info.length,3)*1000)

                songs.append([path ,file ,duration])

               

            elif os.path.isdir(childpath):

                self.findmusic(childpath)

        self.dic = dict(enumerate(songs))

        if not self.dic:

            wx.MessageBox(u'请先导入音乐')

            return

        self.CreatListctrl(self.dic)

        for i in self.dic.keys():

            print(i,self.dic.get(i))

        return self.dic  

    def playmode(self,click):

        if click %3 == 0:  #顺序播放

            self.modebutton.Label = u'顺序播放'

            if self.index == max(self.dic.keys()):

                wx.MessageBox(u'已没有下一曲')

                return

            else:

                nextindex = self.index + 1            

        elif click %3 == 1:#单曲循环

            self.modebutton.Label = u'单曲循环'

            nextindex = self.index

        elif click %3 == 2 :             #随机播放

            self.modebutton.Label = u'随机播放'          

            nextindex = random.choice(list(self.dic.keys()))

        return nextindex

    def playbtn(self): # 播放/暂停按钮的切换

        if not self.dic:

            wx.MessageBox(u'请先导入音乐')

            return

        if  pygame.mixer.music.get_busy(): #已有音乐在播放

            self.playbutton.Label = u'播放'

            self.sst.Label = u'已暂停播放:%s'%self.music

            pygame.mixer.music.pause()

            # pyglet.media.Player.pause()              

        elif pygame.mixer.music.get_pos() == -1: #没有音乐播放过

            self.playbutton.Label = u'暂停'

            self.playing = True

            self.player(self.index)

        else : #从暂停位置播放

            self.playbutton.Label = u'暂停'

            self.playing = True

            pygame.mixer.music.unpause()

            # pyglet.media.Player.play()

            self.sst.Label = u'当前正在播放:%s'%self.music

    def prebutton(self):

        if self.index :

            nextindex = self.index - 1

        elif self.click == 2:

            nextindex = self.playmode(self.click)

        else:

            wx.MessageBox(u'已没有上一曲')

            return

        self.index = nextindex

        self.player(self.index)

    def nextbutton(self):

        if self.index == max(self.dic.keys()):

            wx.MessageBox(u'已没有下一曲')

            return

        elif self.click == 2:

            nextindex = self.playmode(self.click)

        else:

            nextindex = self.index + 1

        self.index = nextindex

        self.player(self.index)

    def btn_handler(self, event):

        eid = event.GetId()    

        if eid == 100:  #导入

            self.findmusic(self.tc.Value)

            self.st.Label = u'当前已选择:%s'%( self.dic[self.index][1])      

        elif eid == 101:#上一曲

            self.prebutton()

        elif eid == 102:#播放/暂停

            self.playbtn()          

        elif eid == 103: #下一曲

            self.nextbutton()

        elif eid == 104:    #播放模式

            self.click += 1

            self.index = self.playmode(self.click)

    def Checkclick(self,event):  #单击行事件

        self.index = event.GetIndex()#行索引

        self.st.Label = u'当前已选择:%s'%( self.dic[self.index][1])

       

    def change_volume(self, evt): #改变音量

        obj = evt.GetEventObject()

        val = obj.GetValue()

        volume = float(val / 100)

        pygame.mixer.music.set_volume(volume)

class MusicPlayer(wx.Frame):

    def __init__(self,parent):

        wx.Frame.__init__(self,parent,style=wx.DEFAULT_FRAME_STYLE)

        self.SetTitle(u'音乐播放器')

        self.SetBackgroundColour((200,200,200))

        self.SetSize(700,400)

        self._init_ui()

        self.Center()

    def _init_ui(self):

        left=panel1(self)

        self._mgr=aui.AuiManager(self,aui.AUI_MGR_TRANSPARENT_HINT)

        self._mgr.SetManagedWindow(self)

        self._mgr.AddPane(left,aui.AuiPaneInfo().CenterPane().Row(0).Position(0).PaneBorder(False))

        self._mgr.Update()

        self.Bind(wx.EVT_CLOSE,self.OnClose)        

    def OnClose(self,event):

        pygame.mixer.music.stop()  #停止播放音乐

        pygame.mixer.quit()         #关闭播放器

        pygame.quit()                #关闭pygame

        self._mgr.UnInit()  #关闭窗口

        self.Destroy()

        # event.Skip()


 

if __name__ =='__main__':

    app=wx.App()

    frame=MusicPlayer(None)

    frame.Show()

    app.MainLoop()

        代码可运行,基于wxpython图形界面、playwright自动化框架以及pygame游戏音乐库,可实现顺序模式、单曲模式、随机循环模式自动播放mp3音乐,同时自动搜索并爬虫下载播放歌词,有需要的同学可以共同学习。

        但在 listctrl中双击播放后再次双击时没有任何响应了,改善的地方还很多,希望各位大佬多多指教,不尽感谢!

  • 15
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
爬虫(Web Crawler)是一种自动化程序,用于从互联网上收集信息。其主要功能是访问网页、提取数据并存储,以便后续分析或展示。爬虫通常由搜索引擎、数据挖掘工具、监测系统等应用于网络数据抓取的场景。 爬虫的工作流程包括以下几个关键步骤: URL收集: 爬虫从一个或多个初始URL开始,递归或迭代地发现新的URL,构建一个URL队列。这些URL可以通过链接分析、站点地图、搜索引擎等方式获取。 请求网页: 爬虫使用HTTP或其他协议向目标URL发起请求,获取网页的HTML内容。这通常通过HTTP请求库实现,如Python中的Requests库。 解析内容: 爬虫对获取的HTML进行解析,提取有用的信息。常用的解析工具有正则表达式、XPath、Beautiful Soup等。这些工具帮助爬虫定位和提取目标数据,如文本、图片、链接等。 数据存储: 爬虫将提取的数据存储到数据库、文件或其他存储介质中,以备后续分析或展示。常用的存储形式包括关系型数据库、NoSQL数据库、JSON文件等。 遵守规则: 为避免对网站造成过大负担或触发反爬虫机制,爬虫需要遵守网站的robots.txt协议,限制访问频率和深度,并模拟人类访问行为,如设置User-Agent。 反爬虫应对: 由于爬虫的存在,一些网站采取了反爬虫措施,如验证码、IP封锁等。爬虫工程师需要设计相应的策略来应对这些挑战。 爬虫在各个领域都有广泛的应用,包括搜索引擎索引、数据挖掘、价格监测、新闻聚合等。然而,使用爬虫需要遵守法律和伦理规范,尊重网站的使用政策,并确保对被访问网站的服务器负责。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值