用 Python 制作音樂聚合下載器

文 |?某某白米飯
來源:Python 技術(shù)「ID: pythonall」

現(xiàn)在的音樂APP有很多,為了不下載很多的APP,所以咱用python做了一個(gè)聚合的音樂下載器,現(xiàn)在聚合了咪咕音樂、QQ音樂,下面是效果圖

安裝
需要安裝一個(gè)輔助模塊 prettytable,用于美化控制臺(tái)的表格輸出
pip?install?prettytable
提取音樂鏈接
搜索音樂
以下載 QQ 音樂為例,在首頁(https://y.qq.com/) 上的搜索框中搜索 <<厚顏無恥>>, 打開 F12 的控制臺(tái)面板,可以找到如下圖的搜索鏈接,這個(gè)鏈接返回的是一個(gè)音樂列表的 json 串

def?get_request(self,?url):
????try:
????????headers?=?{
????????????'User-Agent':?'Mozilla/5.0?(Windows?NT?10.0;?Win64;?x64)?AppleWebKit/537.36?(KHTML,?like?Gecko)?Chrome/85.0.4183.102?Safari/537.36'
????????}
????????response?=?requests.get(url,?headers?=?headers)
????????if?response.status_code?==?200:
????????????return?response
????except?Exception?as?e:
????????print("請(qǐng)求出錯(cuò):",?e)
????????
????return?None
def?search_music(self,?key):
????# 20:?查詢 20?條數(shù)據(jù),key:關(guān)鍵字
????url?=?'https://c.y.qq.com/soso/fcgi-bin/client_search_cp?p=1&n=%d&w=%s'?%?(20,?key)
????resp?=?self.get_request(url)
????resp_json?=?json.loads(resp.text[9:][:-1])
????data_song_list?=?resp_json['data']['song']['list']
????song_list?=?[]
????for?song?in?data_song_list:
????????singers?=?[s.get("name",?"")?for?s?in?song.get("singer",?"")]
????????song_list.append({'name':?song['songname'],?'songmid':?song['songmid'],?'singer':?'|'.join(singers)})
????return?song_list
示例結(jié)果:
[{'name':?'富士山下',?'songmid':?'003dtkNk26WhJD',?'singer':?'陳奕迅'},?{'name':?'不要說話',?'songmid':?'002B2EAA3brD5b',?'singer':?'陳奕迅'},?....,?{'name':?'最佳損友',?'songmid':?'003hFxQh276Cv5',?'singer':?'陳奕迅'}]
獲取下載鏈接
把音樂列表頁中的歌曲點(diǎn)擊到播放音樂的頁面,在控制面板找到多個(gè)以 m4a 結(jié)尾的音樂實(shí)際鏈接

它的參數(shù)部分有一個(gè) vkey 的參數(shù),把 vkey 當(dāng)作關(guān)鍵字在 Network 面板中搜索,找到一個(gè) musics.fcg 結(jié)尾的鏈接,vkey 的數(shù)據(jù)就在它返回的 json 串中,另外的 purl 的值就是上面的 m4a 鏈接,最后將 https://ws.stream.qqmusic.qq.com 和 purl 拼湊成音樂鏈接,musics.fcg 鏈接中 guid 參數(shù)是一個(gè)隨機(jī)數(shù),songmid 參數(shù)是上面單個(gè)音樂的 songmid,uin 參數(shù)是 QQ 號(hào)

def?download_url(self,?song):
????guid?=?str(random.randrange(1000000000,?10000000000))
????purl_url?=?'https://u.y.qq.com/cgi-bin/musicu.fcg?'?\
????????????????'&data={"req":{"param":{"guid":"?%s"}},'?\
????????????????????????'"req_0":{"module":"vkey.GetVkeyServer","method":"CgiGetVkey","param":{"guid":"%s","songmid":["%s"],"uin":"%s"}},"comm":{"uin":%s}}'?\
????????????????%?(guid,?guid,?song['songmid'],?0,?0)
????resp?=?self.get_request(purl_url)
????if?resp?is?None:
????????return?'N',?'None',?'.m4a'
????resp_json?=?json.loads(resp.text)
????purl?=?resp_json['req_0']['data']['midurlinfo'][0]['purl']
????#?有些音樂在網(wǎng)站上不能聽
????if?len(purl)?1:
????????msg?=?'N'
????download_url?=?'http://ws.stream.qqmusic.qq.com/'?+?purl
????song_data?=?self.get_request(download_url)
????if?song_data:
????????msg?=?'Y'
????return?msg,?download_url,?'.m4a'
示例結(jié)果:

只有一個(gè)域名的地址的下載鏈接表示這個(gè)音樂只能在客戶端聽,網(wǎng)頁版聽不了
到這里已經(jīng)完了 QQ 音樂的搜索、抓取腳本,用同樣的方式抓取咪咕音樂(http://m.music.migu.cn)做成咪咕音樂腳本,咪咕音樂更容易爬取
命令行主界面
主界面的主要功能就是以表格的方式顯示搜索到的音樂和以序號(hào)的方式下載音樂
import?os
from?qqMusic?import?QQMusic
from?miguMusic?import?MiGuMusic
from?prettytable?import?PrettyTable
class?MusicBox(object):
????def?__init__(self):
????????pass
????def?download(self,?data,?songName,?type):
????????save_path?=?'music/'?+?songName?+?'.'?+?type
????????file?=?'music'
????????if?os.path.exists(file):
????????????pass
????????else:
????????????os.mkdir('music')
????????try:
????????????print("{}下載中.....".format(songName),?end='')
????????????with?open(save_path,?'wb')?as?f:
????????????????f.write(data)
????????????print("已下載完成")
????????except?Exception?as?err:
????????????print("文件寫入出錯(cuò):",?err)
????????????return?None
????def?main(self):
????????print('請(qǐng)輸入需要下載的歌曲或者歌手:')
????????key?=?input()
????????print('正在查詢..\033[32mQQ音樂\033[0m',?end='')
????????qqMusic?=?QQMusic()
????????qq_song_list?=?qqMusic.main(key)
????????print('...\033[31m咪咕音樂\033[0m')
????????miguMusic?=?MiGuMusic()
????????migu_song_list?=?miguMusic.main(key)
????????qq_song_list.extend(migu_song_list)
????????song_dict?=?{}
????????for?song?in?qq_song_list:
????????????key?=?song['name']?+?'\\'?+?song['singer']
????????????s?=?song_dict.get(key)
????????????if?s:
????????????????if?s['msg']?!=?'Y':
????????????????????song_dict[key]?=?song
????????????else:
????????????????song_dict[key]?=?song
????????i?=?0
????????table?=?PrettyTable(['序號(hào)',?'歌手',?'下載',?'歌名'])
????????table.border?=?0
????????table.align?=?'l'
????????for?song?in?list(song_dict.values()):
????????????i?=?i?+?1
????????????table.add_row([str(i),?song['singer'],?song['msg'],?song['name']])
????????print(table)
????????while?1:
????????????print('\n請(qǐng)輸入需要下載,按 q 退出:')
????????????index?=?input()
????????????if?index?==?'q':
????????????????return
????????????song?=?list(song_dict.values())[int(index)?-?1]
????????????data?=?qqMusic.get_request(song['downloadUrl'])
????????????if?song['msg']?==?'Y':
????????????????self.download(data.content,?song['name'],?song['type'])
????????????else:
????????????????print('該歌曲不允許下載')
if?__name__?==?'__main__':
????musicBox?=?MusicBox()
????musicBox.main()
總結(jié)
音樂聚合下載器最重要的部分還是爬蟲抓取各個(gè)音樂網(wǎng)站的數(shù)據(jù),命令行的方式則省去了畫 GUI 的工作。
PS:公號(hào)內(nèi)回復(fù)「Python」即可進(jìn)入Python 新手學(xué)習(xí)交流群,一起?100 天計(jì)劃!
老規(guī)矩,兄弟們還記得么,右下角的 “在看” 點(diǎn)一下,如果感覺文章內(nèi)容不錯(cuò)的話,記得分享朋友圈讓更多的人知道!


【代碼獲取方式】
