python实现各大平台音乐搜索,下载,收听

再发一遍,旧版本(2021/6/1版本)在这

先上效果图

各大平台的歌随便搜,随便听!

python视频播放器开发 python视频播放器源码_pygame


打包后软件地址:https://wws.lanzoui.com/iosS7rlgzmb 密码: 2gm4 (最好用这个)

下面是源码和测试版:

源码:链接: https://pan.baidu.com/s/1N98jNox7zipVBRcqqkh1Hw 提取码: z6pv

备用链接(github): https://github.com/hedy-bit/pyqt5-pygame-urllib-

大制作,1500多行代python码实现各大平台音乐爬取和,下载和收听,使用了pyqt5,pygame和beautifulsoup



初二暑假没事干,看windows10自带的播放器有一(亿)点点不顺眼,然后再看见网易云之类的平台都要vip,所以想写一个播放器,正好又学了点pyqt5,然后就先整了个离线播音乐放器,耗时4天,后来又添加了爬虫模块,和一些功能模块,就做出来了这个音乐搜索器,支持网易,qq,酷狗,酷我的音乐搜索,下载,收听

分几个部分讲解代码

  • pyqt5界面
  • python爬虫
  • 下载
  • 功能模块
    爬虫线程,下载线程和进度条线程我都是新开了类的,因为在主线程进行爬虫会有一定的概率会触发关闭

界面

快不多说,先上代码

界面的话。。。我觉得挺好看的,由于代码太长我就不放出来了

python视频播放器开发 python视频播放器源码_爬虫_02

pyhton爬虫

由于怕被各大平台起诉,所以都是通过第三方平台爬虫的
爬取搜索的歌曲,歌手和url,由于要使用多线程,所以新开了一个类

class PAThread(QThread):
    # 自定义信号对象。参数str就代表这个信号可以传一个字符串
    trigger = pyqtSignal(str)

    def __int__(self):
        # 初始化函数
        super(PAThread, self).__init__()

    def run(self):
        qmut.lock()
        try:
            global paing
            global stop
            global lrcs
            global urls
            global songs
            global name
            global songid
            global proxies
            global pic
            global tryed
            paing = True

            print('搜索软件{}'.format(type))
            print('开始搜索')
            name = name
            headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.110.430.128 Safari/537.36',
                'X-Requested-With': 'XMLHttpRequest'

            }
            urls = []
            songs = []
            pic = []
            lrcs = []
            if int(page) == '' or int(page) < 1:
                pages = 2
            else:
                pages = int(page)
            print(pages)
            for a in range(1, pages + 1):
                if not stop:

                    urlss = ['http://music.9q4.cn/', 'https://defcon.cn/dmusic/', 'http://www.xmsj.org/',
                             'http://music.laomao.me/']
                    print(tryed)
                    if tryed > 3:

                        tryed = 0
                        url = urlss[tryed]
                    else:
                        url = urlss[tryed]
                    print(urlss[tryed])

                    params = {'input': name,
                              'filter': 'name',
                              'type': type,
                              'page': a
                              }
                    if not stop:
                        try:
                            res = post(url, params, headers=headers, proxies=proxies)
                            html = res.json()

                            for i in range(0, 10):

                                try:
                                    title = jsonpath(html, '$..title')[i]
                                    author = jsonpath(html, '$..author')[i]
                                    url1 = jsonpath(html, '$..url')[i]  # 取下载网址
                                    pick = jsonpath(html, '$..pic')[i]  # 取歌词
                                    lrc = jsonpath(html, '$..lrc')[i]
                                    print(title, author)
                                    lrcs.append(lrc)
                                    urls.append(url1)
                                    pic.append(pick)
                                    songs.append(str(title) + ' - ' + str(author))
                                    # self.textEdit.setText(lrc)  # 打印歌词
                                    # print(lrc)
                                except:
                                    pass
                        except:
                            stop = False
                            paing = False

                        print(urls)
                        print(songs)
                        self.trigger.emit(str('finish'))
                    else:
                        print('stop')
                        self.trigger.emit(str('finish'))
                else:
                    print('stop')
                    self.trigger.emit(str('clear'))
                    pass

            stop = False
            paing = False
        except:
            print('爬取歌曲出错')
            self.trigger.emit(str('unfinish'))
            stop = False
            paing = False
        qmut.unlock()

然后就是从爬取的url下载歌曲

python视频播放器开发 python视频播放器源码_爬虫_03

歌曲下载!

class WorkThread(QThread):
    # 自定义信号对象。参数str就代表这个信号可以传一个字符串
    trigger = pyqtSignal(str)

    def __int__(self):
        # 初始化函数
        super(WorkThread, self).__init__()

    def cbk(self, a, b, c):
        '''''回调函数
        @a:已经下载的数据块
        @b:数据块的大小
        @c:远程文件的大小
        '''
        per = 100.0 * a * b / c
        if per > 100:
            per = 100
        # print   ('%.2f%%' % per)
        self.trigger.emit(str('%.2f%%' % per))

    def run(self):
        global to
        global number
        global path
        global downloading
        global pic
        global lrct
        global lrcd
        if bo == 'boing':
            try:
                proxies = {
                    'http': 'http://124.72.109.183:8118',
                    ' Shttp': 'http://49.85.1.79:31666'

                }
                headers = {
                    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36',
                    'X-Requested-With': 'XMLHttpRequest'}
                try:
                    try:
                        try:
                            aq = pic[num]
                            aqq = aq.split('/')

                        except:
                            pass

                        if type == 'kugou' and len(aqq) - 1 == 6:
                            aqqe = str(aqq[0]) + str('//') + str(aqq[2]) + str('/') + str(aqq[3]) + str('/') + str(
                                '400') + str('/') + str(aqq[5]) + str('/') + str(aqq[6])
                            print(aqqe)
                        elif type == 'netease' and len(aqq) - 1 == 4:
                            aqn = aq.split('?')
                            b = '?param=500x500'
                            aqqe = (str(aqn[0]) + str(b))
                            print(aqqe)
                        else:
                            aqqe = pic[num]
                        req = get(aqqe)

                        checkfile = open(str(data + '/ls1.png'), 'w+b')
                        for i in req.iter_content(100000):
                            checkfile.write(i)

                        checkfile.close()
                        lsfile = str(data + '/ls1.png')
                        safile = str(data + '/back.png')
                        draw(lsfile, safile)
                    except:
                        pass
                    url1 = urls[num]
                    print(url1)
                    number = number + 1
                    path = str(data + '\{}.临时文件'.format(number))
                    headers = {
                        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.110.430.128 Safari/537.36',
                        'X-Requested-With': 'XMLHttpRequest'
                    }
                    with get(url1, stream=True, headers=headers) as r, open(path, 'wb') as file:
                        total_size = int(r.headers['content-length'])
                        content_size = 0
                        for content in r.iter_content(chunk_size=1024):
                            file.write(content)
                            content_size += len(content)
                            plan = (content_size / total_size) * 100
                            # print(int(plan))
                            develop = str(int(plan)) + str('%')
                            self.trigger.emit(str(develop))
                    to = 'downloadmusic\{}.mp3'.format(songs[num])
                    makedirs('downloadmusic', exist_ok=True)
                except:
                    pass
                try:
                    if bo == 'boing':
                        lrct = []
                        f = lrcs[num]  # 按行读取
                        # print (f)
                        lines = f.split('\n')
                        # print (lines)
                        if not lines == ['']:
                            for i in lines:
                                if not i == '':
                                    line1 = i.split('[')
                                    try:
                                        line2 = line1[1].split(']')
                                        if line2 == '':
                                            pass
                                        else:
                                            linew = line2[1]
                                            # print(linew)
                                            lrct.append(linew)
                                        self.trigger.emit(str('lrcfinish'))
                                    except:
                                        print('{}的歌词错误'.format(str(line1)))
                                else:
                                    pass
                        else:
                            self.trigger.emit(str('lrcnofinish'))
                            print('没有歌词')
                except:
                    print('歌词错误')
                try:
                    copyfile(path, to)
                except:
                    pass
                downloading = False
                self.trigger.emit(str('finish'))

            except:
                self.trigger.emit(str('nofinish'))

列表点击播放

下面就是QListwidge的点击和播放模块

def bofang(self, num):
        print ('try bofang')
        try:
            import urllib
            global pause
            global songs
            global music
            global downloading
            downloading = True
            self.console_button_3.setIcon(qtawesome.icon('fa.pause', color='#F76677', font=18))
            pause = False
            # QMessageBox.information(self, "ListWidget", "你选择了: "+item.text())# 显示出消息提示框
            try:
                pygame.mixer.stop()
            except:
                pass
            pygame.mixer.init()
            try:
                self.Timer = QTimer()
                self.Timer.start(500)
            except:
                pass


            try:
                self.label.setText('下载中')#调用开头的多线程下载歌曲
                self.work = WorkThread()
                self.work.start()
                self.work.trigger.connect(self.display)
            except:
                print ('song download error')
                downloading = False
                pass




        except:
            time.sleep(0.1)
            print ('system error')
            #self.next()
            pass
	#用于接收返回的信号
    def display(self,sd):
        if sd == 'finish':
            self.label.setText(songs[num])
            print ('music\{}.mp3'.format(number))
            pygame.mixer.music.load('music\{}.mp3'.format(number))  # 载入音乐
            pygame.mixer.music.play()
            # 播放音乐
        else:
            self.label.setText('下载错误')

功能函数

下面是双击播放和上一首还有下一首

#QlistWidget的双击事件
    def change_func(self, listwidget):
        global num
        item = QListWidgetItem(self.listwidget.currentItem())
        print(item.text())
        
        num = int(listwidget.currentRow())
        
        self.label.setText(songs[num])
        print(listwidget.currentRow())
        self.bofang(num)
		
	#下一首按钮
	def nextion(self):

            try:
                    if play == 'shun':
                        print('shuning')
                        self.next()
                    elif play == 'shui':
                        print('shuiing')
                        self.shui()
                    elif play == 'always':
                        print('alwaysing')
                        self.next()

            except:
                print('no')
                pass

下面自动播放,有循环,随机和单曲循环,加上下一首,上一首,

#随机播放
    def shui(self):
        global num
        global songs
        q = int(len(songs) - 1)
        num = int(random.randint(1, q))
        try:
            print('shui')
            pygame.mixer.init()
            self.Timer = QTimer()
            self.Timer.start(500)
            # self.Timer.timeout.connect(self.timercontorl)#时间函数,与下面的进度条和时间显示有关
            self.label.setText(songs[num])
            self.bofang(num) # 播放音乐

        except:
            pass
	#下一首
    def next(self):
        print ('nexting')
        global num
        global songs
        if num == len(songs) - 1:
            print('冇')
            num = 0
        else:
            num = num + 1
        try:
            self.label.setText(songs[num])
            self.bofang(num)
        except:
            print ('next error')
            pass


	#单曲循环
    def always(self):
        try:
            self.bofang(num)
            self.label.setText(songs[num])

        except:
            pass
	#上一首
    def last(self):
        global num
        global songs
        if num == 0:
            print('冇')
            num = len(songs) - 1
        else:
            num = num - 1
        try:
            self.bofang(num)
            self.label.setText(songs[num])

        except:
            pass

下面是播放模式选择和循环判断是否要自动下一首
由于每秒钟判断一次,所以要使用多线程

'''
		在init里面的循环判断打开方法
	    t1 = threading.Thread(target=self.action)
        t1.setDaemon(True)
        t1.start()
    '''
	#选择播放模式
    def playmode(self):
        global play
        try:
            if play == 'shun':
                play = 'shui'
                print('随机播放')
                self.label2.setText("当前为随机播放")
                try:
                    self.console_button_6.setIcon(qtawesome.icon('fa.random', color='#3FC89C', font=18))
                    print('done')
                except:
                    print('none')
                    pass

                # self.left_shui.setText('切换为单曲循环')
            elif play == 'shui':
                play = 'always'
                print('单曲循环')
                self.label2.setText("当前为单曲循环")
                try:
                    self.console_button_6.setIcon(qtawesome.icon('fa.retweet', color='#3FC89C', font=18))
                    print('done')
                except:
                    print('none')


                # self.left_shui.setText('切换为顺序播放')
            elif play == 'always':
                play = 'shun'
                print('顺序播放')
                self.label2.setText("当前为顺序播放")
                try:
                    self.console_button_6.setIcon(qtawesome.icon('fa.align-center', color='#3FC89C', font=18))
                    print('done')
                except:
                    print('none')

                # self.left_shui.setText('切换为随机播放')
        except:
            print('error')
            pass
	#循环判断
    def action(self):
        a = 1
        global num
        while a < 2:
            # print ('checking')
            try:
                time.sleep(1)
                if not pygame.mixer.music.get_busy() and pause == False and not downloading:
                    if play == 'shun':
                        print('shuning')
                        self.next()
                    elif play == 'shui':
                        print('shuiing')
                        self.shui()
                    elif play == 'always':
                        print('alwaysing')
                        self.always()

            except:
                print('no')
                pass
        else:
            pygame.mixer.music.stop()

还有就是进度条,线程

class barThread(QThread):
    # 自定义信号对象。参数str就代表这个信号可以传一个字符串
    trigger = pyqtSignal(str)

    def __int__(self):
        # 初始化函数
        super(barThread, self).__init__()

    def run(self):
        xun4 = 1
        # print ('begin')
        try:

            # print ('check')
            sleep(1)
            try:
                try:
                    global timenum
                    xun4 = 1
                    while xun4 < 2:
                        sleep(1)
                        # print ('check')
                        if not downloading or not paing:
                            try:
                                # print ('check pass')
                                timenumm = timenum * 10000
                                # print (timenumm)
                                current = mixer.music.get_pos()  # 毫秒
                                current %= timenumm
                                assq = current / timenumm * 10000
                                # print(current)

                                assq = int(assq * 10)
                                # print(assq)
                                if not assq > 10000:
                                    self.trigger.emit(str(assq))

                                else:
                                    assq = 10000
                                    self.trigger.emit(str(assq))

                            except:
                                try:
                                    if mixer.music.get_busy():
                                        print('进度条错误')
                                except:
                                    pass
                except:
                    pass


            except:
                pass
        except:
            pass