python實戰:50行代碼讓你輕鬆下載QQ音樂VIP歌曲

**1、**此處以下載《李榮浩—年少有爲》爲目標歌曲,首先我們來到QQ音樂網頁版搜索歌曲:https://y.qq.com/portal/search.html#page=1&searchid=1&remoteplace=txt.yqq.top&t=song&w=年少有爲 ,搜索到目標歌曲有許多版本。點擊第一首來到播放頁面,如下圖操作打開chrome的開發者工具後切換到Network,重新刷新頁面,找到請求到這首歌曲播放源的URL。
在這裏插入圖片描述
將上圖的鏈接:http://dl.stream.qqmusic.qq.com/C400004DXFlC0nsTCZ.m4a?guid=602087500&vkey=3077FD9F94F9BFB3DF0544C32123C188D12042C45C22FDE8B19694D79C68A6A045EEB7F9D11598249BF43F7649684353E5DE8DEF10A50417&uin=0&fromtag=66 在另一個標籤頁打開可以聽到該歌曲正常地播放,因此這個就是我們需要找的播放源。爲了獲取這個播放源數據,我們得先製造這個歌曲資源的URL,而這個歌曲資源的URL裏vkey(祕鑰)是由QQ音樂專門的祕鑰服務器生成的,這時候就要去找哪個文件裏保存了服務器返回的祕鑰。

**2、**將上圖的Network中切換到XHR,按下圖經過一番查看你會看到這個文件在這裏插入圖片描述
其中就有我們所需要的數據,且可以看到我們只要能夠提取出purl再和http://dl.stream.qqmusic.qq.com/ 進行拼接就能得到播放源的數據了。在上圖文件中我們切換到Headers查看其請求的URL https://u.y.qq.com/cgi-bin/musicu.fcg?-=getplaysongvkey3279590927017204&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0&data={“req”%3A{“module”%3A"CDN.SrfCdnDispatchServer"%2C"method"%3A"GetCdnDispatch"%2C"param"%3A{“guid”%3A"602087500"%2C"calltype"%3A0%2C"userip"%3A""}}%2C"req_0"%3A{“module”%3A"vkey.GetVkeyServer"%2C"method"%3A"CgiGetVkey"%2C"param"%3A{“guid”%3A"602087500"%2C"songmid"%3A[“004DXFlC0nsTCZ”]%2C"songtype"%3A[0]%2C"uin"%3A"0"%2C"loginflag"%3A1%2C"platform"%3A"20"}}%2C"comm"%3A{“uin”%3A0%2C"format"%3A"json"%2C"ct"%3A24%2C"cv"%3A0}}
,會看到比較亂,這是因爲這個URL被編碼了,我用chrome插件按下圖操作對其進行解碼:
在這裏插入圖片描述
解碼後的URL爲:https://u.y.qq.com/cgi-bin/musicu.fcg?-=getplaysongvkey3279590927017204&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0&data={“req”:{“module”:“CDN.SrfCdnDispatchServer”,“method”:“GetCdnDispatch”,“param”:{“guid”:“602087500”,“calltype”:0,“userip”:""}},“req_0”:{“module”:“vkey.GetVkeyServer”,“method”:“CgiGetVkey”,“param”:{“guid”:“602087500”,“songmid”:[“004DXFlC0nsTCZ”],“songtype”:[0],“uin”:“0”,“loginflag”:1,“platform”:“20”}},“comm”:{“uin”:0,“format”:“json”,“ct”:24,“cv”:0}} 。爲了獲取到purl我們需對這個URL進行一些測試,看下這些參數是否都必須要有,進過多次測試我得到簡化後的URL爲:https://u.y.qq.com/cgi-bin/musicu.fcg?data={“req_0”:{“module”:“vkey.GetVkeyServer”,“method”:“CgiGetVkey”,“param”:{“guid”:“602087500”,“songmid”:[“004DXFlC0nsTCZ”],“songtype”:[0],“uin”:“0”,“loginflag”:1,“platform”:“20”}},“comm”:{“uin”:0,“format”:“json”,“ct”:24,“cv”:0}} ,其返回結果如下圖:
在這裏插入圖片描述
通過對比不同歌曲的URL發現其中的songmid不同外其它基本相同,但guid不太確定是否會一直不變,因此我按下圖進行全局搜索找到定義該guid的文件。
在這裏插入圖片描述
可以看到guid其實是隨機生成的,所以我們可以一直用一個固定值,此處就一直用上面URL中的guid值,因此我們只需獲得songmid即可。

**3、**爲了找到songmid,我們回到一開始的搜索頁面https://y.qq.com/portal/search.html#page=1&searchid=1&remoteplace=txt.yqq.top&t=song&w=%E5%B9%B4%E5%B0%91%E6%9C%89%E4%B8%BA ,如下圖操作打開chrome的開發者工具後切換到Network,重新刷新頁面,找到songmid的值。
在這裏插入圖片描述
可以看到songmid的值就是mid,切換到Headers查看請求的URL爲:https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=txt.yqq.song&searchid=55391003577889450&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=1&n=20&w=年少有爲&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0 ,對這個URL進行一些測試,看下哪些參數是否都必須要有,進過多次測試我得到簡化後的URL爲:https://c.y.qq.com/soso/fcgi-bin/client_search_cp?new_json=1&remoteplace=txt.yqq.song&t=0&aggr=1&cr=1&w=年少有爲&format=json&platform=yqq.json
,也就是說我們只需更改歌曲名即可,簡化後的結果如下圖。
在這裏插入圖片描述
**4、**綜合上述分析,我們開始敲代碼,以下是我的全部源碼,50行不到:

from requests_html import HTMLSession
import urllib.request,os,json
from urllib.parse import quote

class QQ_Music():
    def __init__(self):
        self.get_music_url='https://c.y.qq.com/soso/fcgi-bin/client_search_cp?new_json=1&remoteplace=txt.yqq.song&t=0&aggr=1&cr=1&w={}&format=json&platform=yqq.json'
        self.get_song_url='https://u.y.qq.com/cgi-bin/musicu.fcg?data={"req_0":{"module":"vkey.GetVkeyServer","method":"CgiGetVkey","param":{"guid":"602087500","songmid":["%s"],"songtype":[0],"uin":"0","loginflag":1,"platform":"20"}},"comm":{"uin":0,"format":"json","ct":24,"cv":0}}'
        self.download_url='http://dl.stream.qqmusic.qq.com/'
        if not os.path.exists("d:/music"):
            os.mkdir('d:/music')

    def parse_url(self,url):
        session = HTMLSession()
        response = session.get(url)
        return response.content.decode()

    def get_music_list(self,keyword):
        music_dirt=json.loads(self.parse_url(self.get_music_url.format(quote(keyword))))
        music_list=music_dirt['data']['song']['list']
        # print(music_list)
        song_list=[]
        for music in music_list:
            sing_name=music['singer'][0]['name']
            song_name=music['title_hilight'].replace(r"</em>", "").replace("<em>", "")
            song_list.append({'songmid':music['mid'], 'singer':sing_name,'song_name':song_name})
            print(str(len(song_list))+'、'+sing_name+'--'+song_name)
        return song_list

    def download(self,song):
        song_dirt = json.loads(self.parse_url(self.get_song_url%song['songmid']))
        download_url = song_dirt["req_0"]["data"]["midurlinfo"][0]["purl"]
        if download_url:
            try:
                # 根據音樂url地址,用urllib.request.retrieve直接將遠程數據下載到本地
                urllib.request.urlretrieve(self.download_url+download_url, 'd:/music/' + song['song_name'] + '.mp3')
                print('Successfully Download:' + song['singer']+'--'+song['song_name'] + '.mp3')
            except:
                print('Download wrong~')
if __name__ == '__main__':
    qqmusic=QQ_Music()
    while True:
        keyword = input('請輸入要下載的歌曲名:')
        print('-----------歌曲《' + keyword + '》的版本列表------------')
        music_list = qqmusic.get_music_list(keyword)
        song_num = input('請輸入要下載的歌曲序號:')
        qqmusic.download(music_list[int(song_num) - 1])

敲完發現和上次寫酷狗音樂的差不多,以下是運行結果:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章