pyqt5+pygame+urllib+beautiful實現各大平臺(網易,酷狗,qq)音樂爬取和收聽,下載,最終版本
阿新 • • 發佈:2021-06-27
全部原始碼在https://github.com/hedy-bit/pyqt5-pygame-urllib-
先上效果圖
之前沒事幹,看windows10自帶的播放器有一(億)點點不順眼,然後想寫一個播放器,
正好有學了點pyqt5,然後就整了個離線播音樂放器,耗時4天,現在差不多也算是最終版本了吧,
如果接下來有時間的話也會繼續更新下去,連結:離線播放器連結
然後最近沒有事情要做,就寫了一個網路音樂播放器,結構跟離線版本差不多主要更新了邏輯,添加了爬蟲模組
快不多說,先上程式碼
首先是爬取搜尋的歌曲,歌手和url,由於要使用多執行緒,所以新開了一個類
class PAThread(QThread): # 自定義訊號物件。引數str就代表這個訊號可以傳一個字串 trigger = pyqtSignal(str) def __int__(self): # 初始化函式 super(PAThread, self).__init__() def get_info(self, url): global proxies global tryed print('start get info') print(tryed) headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/491.10.2623.122 Safari/537.36' } web_data = requests.get(url, headers=headers) soup = BeautifulSoup(web_data.text, 'lxml') ranks = soup.select('#list > table > tbody > tr:nth-child({}) > td:nth-child(1)'.format(str(tryed))) titles = soup.select('#list > table > tbody > tr:nth-child({}) > td:nth-child(2)'.format(str(tryed))) times = soup.select('#list > table > tbody > tr:nth-child({}) > td:nth-child(6)'.format(str(tryed))) for rank, title, time in zip(ranks, titles, times): data = { 'IP': rank.get_text(), 'duan': title.get_text(), 'time': time.get_text() } q = str('http://' + str(rank.get_text()) + '/' + str(title.get_text())) proxies = { 'http': q } print(proxies) def run(self): qmut.lock() try: global urls global songs global name global songid global proxies global pic print('type') print('begin looking') url = 'https://defcon.cn/dmusic/' name = name self.get_info('https://www.kuaidaili.com/free/inha') print(proxies) 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 = [] if int(page) == '' or int(page) < 1: pages = 2 else: pages = int(page) print(pages) for a in range(1, pages): params = {'input': name, 'filter': 'name', 'type': type, 'page': a } res = requests.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] # 取歌詞 print(title, author) urls.append(url1) pic.append(pick) songs.append(str(title) + ' - ' + str(author)) # self.textEdit.setText(lrc) # 列印歌詞 # print(lrc) except: pass print(urls) print(songs) self.trigger.emit(str('finish')) except: print('pa error') self.trigger.emit(str('unfinish')) qmut.unlock()
然後就是從爬取的url下載歌曲,由於我設計了兩個歌單,所以我寫了兩個類
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): try: global number global path global downloading global pic 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=400x400' aqqe = (str(aqn[0]) + str(b)) print(aqqe) else: aqqe = pic[num] req = requests.get(aqqe) checkfile = open('./music/ls1.png', 'w+b') for i in req.iter_content(100000): checkfile.write(i) checkfile.close() lsfile = './music/ls1.png' safile = './music/back.png' draw(lsfile, safile) except: pass url1 = urls[num] print(url1) os.makedirs('music', exist_ok=True) number = number + 1 path = 'music\{}.臨時檔案'.format(number) urlretrieve(url1, path, self.cbk) # 下載函式的使用 to = 'downloadmusic\{}.mp3'.format(songs[num]) os.makedirs('downloadmusic', exist_ok=True) except: pass try: copyfile(path, to) except: pass downloading = False self.trigger.emit(str('finish')) except: self.trigger.emit(str('nofinish')) class WorkThread2(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): try: global number global path global downloading proxies = { 'http': 'http://124.72.109.183:8118', 'http': '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: if type == 'kugou': aq = picd[num] aqq = aq.split('/') 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) else: aqqe = picd[num] req = requests.get(aqqe) checkfile = open('./music/ls1.png', 'w+b') for i in req.iter_content(100000): checkfile.write(i) checkfile.close() lsfile = './music/ls1.png' safile = './music/back.png' draw(lsfile, safile) url1 = urled[num] print(url1) os.makedirs('music', exist_ok=True) number = number + 1 path = 'music\{}.臨時檔案'.format(number) urlretrieve(url1, path, self.cbk) # 下載函式的使用 to = 'downloadmusic\{}.mp3'.format(songed[num]) os.makedirs('downloadmusic', exist_ok=True) except: pass 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()
程式碼介紹在這裡就結束了,如果有更好的修改方案請私信我