QQ音樂相比於網易雲音樂加密部分基本上沒有,但是就是QQ音樂的頁面與頁面之間的聯系太強了,,導致下載一個音樂需要分析前面多個頁面,找數據。。太繁瑣了
1、爬取鏈接:https://y.qq.com/
首先隨便找一個頁面先點進去
2、點擊播放歌曲會打開一個頁面,按F12打開控制台,然后刷新頁面並點擊播放歌曲,network里面就會有數據包
3、在控制台選中media,找到下圖這樣類型的文件,它的request url就是歌曲播放url,如下下圖
當然,我們肯定不能每下載一首歌都這樣,一是這樣很麻煩,二是遇到vip等音樂,你在線都不能播放,你還怎么找到歌曲鏈接
所以,分析頁面是必然的!!!我們首先分析一下這個歌曲播放鏈接的url
https://isure.stream.qqmusic.qq.com/C400002AskAI4LWf5i.m4a?guid=8487932120&vkey=65570474D22ADFAB32FE60DA30EA32CB618422B773A49AE5FA2158C071D4C51931D28B15D823E1BA87BCA837EC09A0FCF8BD9E2763D46B91&uin=0&fromtag=66
我們對這個url進行刪減(因為url有些部分都不需要,我們為了看起來更直觀要對其進行處理)
#精簡后url https://isure.stream.qqmusic.qq.com/C400002AskAI4LWf5i.m4a?guid=8487932120&vkey=65570474D22ADFAB32FE60DA30EA32CB618422B773A49AE5FA2158C071D4C51931D28B15D823E1BA87BCA837EC09A0FCF8BD9E2763D46B91
我們大致一看它的url,就知道頁面提交用get將參數guid和vkey追加到url地址后面,那么我們就要去找vkey和guid參數是怎么來的
guid參數:
你多打開幾個歌曲就會發現它的guid都是一樣的,所以這個我們就不用管
vkey參數:
這個參數難為死我了,我剛開始以為它和網易雲音樂一樣也是加密一下,然后我就去js文件里面找,找了半天沒找到賦值語句,我就納悶了,以為這是更高級的加密,,,,然后看了半天js,最后終於確定,js和這個沒啥關系。。。。。。。
之后感覺分析頁面分析不動了,上網找了篇博客給了我靈感,雖然那篇博客代碼已經過時了,但是它啟發了我 “播放歌曲的鏈接可能不止一個”
於是我又開始找vkey在哪個數據包出現過,如下圖
我找到了vkey且對比了一下和之前鏈接上vkey的值一樣,你再仔細看就會發現那個歌曲下載鏈接就是
https://isure.stream.qqmusic.qq.com/加上purl的值。(我giao!!)
然后就要去分析這個數據包的請求頭了(嗚嗚嗚~),請求頭如下(好長~~~)
https://u.y.qq.com/cgi-bin/musics.fcg?-=getplaysongvkey6574047973093009&g_tk=1740745507&sign=zzaztgck8xaqpsxorw45ed952a339dbe91c7990f803cb9a6f1&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq.json&needNewCode=0&data=%7B%22req_0%22%3A%7B%22module%22%3A%22vkey.GetVkeyServer%22%2C%22method%22%3A%22CgiGetVkey%22%2C%22param%22%3A%7B%22guid%22%3A%228487932120%22%2C%22songmid%22%3A%5B%22003cGaJY10RAsX%22%5D%2C%22songtype%22%3A%5B0%5D%2C%22uin%22%3A%220%22%2C%22loginflag%22%3A1%2C%22platform%22%3A%2220%22%7D%7D%2C%22comm%22%3A%7B%22uin%22%3A0%2C%22format%22%3A%22json%22%2C%22ct%22%3A24%2C%22cv%22%3A0%7D%7D
這個時候我就遇到一個坑點(QQ音樂有毒),這么長的鏈接我們肯定要對其進行刪減,好看看哪些參數有用,哪些參數用來混亂我們的視線
但是如果你前面的一段鏈接改為
https://u.y.qq.com/cgi-bin/musicu
你就能對很多參數進行刪除,就最后一個字母不一樣,但是對參數進行刪除的時候前面那個鏈接就基本上參數都不能刪除
這讓我就很難受,我的訪問鏈接就是
https://u.y.qq.com/cgi-bin/musics
這一部分,但是有些人訪問鏈接是
https://u.y.qq.com/cgi-bin/musicu
化簡之后鏈接就變成了
https://u.y.qq.com/cgi-bin/musicu.fcg?format=json&data=%7B%22req_0%22%3A%7B%22module%22%3A%22vkey.GetVkeyServer%22%2C%22method%22%3A%22CgiGetVkey%22%2C%22param%22%3A%7B%22guid%22%3A%22358840384%22%2C%22songmid%22%3A%5B%22{}%22%5D%2C%22songtype%22%3A%5B0%5D%2C%22uin%22%3A%221443481947%22%2C%22loginflag%22%3A1%2C%22platform%22%3A%2220%22%7D%7D%2C%22comm%22%3A%7B%22uin%22%3A%2218585073516%22%2C%22format%22%3A%22json%22%2C%22ct%22%3A24%2C%22cv%22%3A0%7D%7D".format(mid值)
與其他歌曲的這個鏈接對比一下就會發現只有songmid的值再改變
我們再去找songmid是什么,瘋狂在文件中尋找,結果沒有songmid字樣,有也是在js中,songmid在js中還多以注釋出現。。。
之后我在搜索歌曲之后,在歌曲信息的數據包里面發現了mid,然后我把url地址中編碼過的mid解碼后發現它們一樣。。。(牛掰!!!)
下面給一個在多個文件中快速搜索關鍵子字的方法,如下圖:
在線url解碼:http://tool.chinaz.com/tools/urlencode.aspx
以搜索“夕陽紅為例”
數據包list字段下面就是歌曲信息
然后再看一下這個數據包的請求頭(希望不要麻煩)
https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=txt.yqq.song&searchid=70921863029222715&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=1&n=10&w=%E5%A4%95%E9%98%B3%E7%BA%A2&g_tk_new_20200303=1740745507&g_tk=1740745507&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq.json&needNewCode=0
刪減之后
https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=txt.yqq.song&searchid=70631360004412645&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=1&n=10&w=%E9%9D%9E%E9%B1%BC&g_tk_new_20200303=5381&g_tk=5381&loginUin=2272463882&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq.json&needNewCode=0
通過歸納可以知道n代表搜索到的歌曲顯示數目,w是搜索的關鍵字
所以我們n設定一個值就行,w就運行程序是輸入就行
所有問題都解決了(呼~~~~~~~)
import requests import re import os import json import time as t class QQmusic(): """代碼僅供學習""" def __init__(self): """初始化""" self.headers = { 'Accept-Encoding': 'gzip, deflate, sdch', 'Accept-Language': 'en-US,en;q=0.8', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Referer': 'http://www.baidu.com/', 'Connection': 'keep-alive', } self.names = [] self.order = ' ' def search(self): """搜索""" w = input("請輸入歌曲名: ") url_0 = "https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=txt.yqq.song&searchid=61460539676714578&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=1&n=10&w={0}&g_tk_new_20200303=5381&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq.json&needNewCode=0".format( w) res_0 = requests.get(url_0, headers=self.headers) # 第一層,搜索頁 res_0.encoding = res_0.apparent_encoding res_0 = res_0.json() # dict music_list = res_0["data"]["song"]["list"] print("共計" + str(len(music_list)) + "結果: ") all_singers = [] a = 0 for music in music_list: singer = music["singer"][0]["title"] # 歌手名 name = str(a) + " " + music["title"] # 歌曲名 all_singers.append(singer) self.names.append(name) a = a + 1 infs = dict(zip(self.names, all_singers)) infs = json.dumps(infs, ensure_ascii=False, indent=4, separators=(',', ':')) infs = infs.replace('"', ' ') infs = infs.replace(':', '——————') print(infs) self.order = input("請輸入歌曲前的序號:") songmid = res_0['data']['song']['list'][int(self.order)]['mid'] url_1 = "https://u.y.qq.com/cgi-bin/musicu.fcg?format=json&data=%7B%22req_0%22%3A%7B%22module%22%3A%22vkey.GetVkeyServer%22%2C%22method%22%3A%22CgiGetVkey%22%2C%22param%22%3A%7B%22guid%22%3A%22358840384%22%2C%22songmid%22%3A%5B%22{}%22%5D%2C%22songtype%22%3A%5B0%5D%2C%22uin%22%3A%221443481947%22%2C%22loginflag%22%3A1%2C%22platform%22%3A%2220%22%7D%7D%2C%22comm%22%3A%7B%22uin%22%3A%2218585073516%22%2C%22format%22%3A%22json%22%2C%22ct%22%3A24%2C%22cv%22%3A0%7D%7D".format(songmid) res_1 = requests.get(url_1, headers=self.headers) res_1.encoding = res_1.apparent_encoding res_1 = res_1.json() # dict purl = res_1['req_0']['data']['midurlinfo'][0]['purl'] url_2 = "https://isure.stream.qqmusic.qq.com/" + purl return url_2 def download(self): """下載""" res_2 = requests.get(self.search(), headers=self.headers).content fir = self.names[int(self.order)] tit = re.sub(r'\d+', '', fir) now = os.getcwd() now = os.path.join(now, "qq音樂 ") if not os.path.exists(now): os.mkdir(now) os.chdir(now) file_name = tit + '.m4a' with open(file_name, 'wb') as f: f.write(res_2) one_file = QQmusic() one_file.download()