用 Python 製做音樂聚合下載器

用 Python 製做音樂聚合下載器

文 | 某某白米飯python

來源:Python 技術「ID: pythonall」json

用 Python 製做音樂聚合下載器

如今的音樂APP有不少,爲了避免下載不少的APP,因此咱用python作了一個聚合的音樂下載器,如今聚合了咪咕音樂、QQ音樂,下面是效果圖app

用 Python 製做音樂聚合下載器

安裝

須要安裝一個輔助模塊 prettytable,用於美化控制檯的表格輸出dom

pip install prettytable

提取音樂連接

搜索音樂

如下載 QQ 音樂爲例,在首頁(https://y.qq.com/) 上的搜索框中搜索 <<厚顏無恥>>, 打開 F12 的控制檯面板,能夠找到以下圖的搜索連接,這個連接返回的是一個音樂列表的 json 串ide

用 Python 製做音樂聚合下載器

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("請求出錯:", e)

    return None

def search_music(self, key):
    # 20: 查詢 20 條數據,key:關鍵字
    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

示例結果:網站

[{'name': '富士山下', 'songmid': '003dtkNk26WhJD', 'singer': '陳奕迅'}, {'name': '不要說話', 'songmid': '002B2EAA3brD5b', 'singer': '陳奕迅'}, ...., {'name': '最佳損友', 'songmid': '003hFxQh276Cv5', 'singer': '陳奕迅'}]

獲取下載連接

把音樂列表頁中的歌曲點擊到播放音樂的頁面,在控制面板找到多個以 m4a 結尾的音樂實際連接ui

用 Python 製做音樂聚合下載器

它的參數部分有一個 vkey 的參數,把 vkey 看成關鍵字在 Network 面板中搜索,找到一個 musics.fcg 結尾的連接,vkey 的數據就在它返回的 json 串中,另外的 purl 的值就是上面的 m4a 連接,最後將 https://ws.stream.qqmusic.qq.com 和 purl 拼湊成音樂連接,musics.fcg 連接中 guid 參數是一個隨機數,songmid 參數是上面單個音樂的 songmid,uin 參數是 QQ 號url

用 Python 製做音樂聚合下載器

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']

    # 有些音樂在網站上不能聽
    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'

示例結果:命令行

用 Python 製做音樂聚合下載器

只有一個域名的地址的下載連接表示這個音樂只能在客戶端聽,網頁版聽不了3d

到這裏已經完了 QQ 音樂的搜索、抓取腳本,用一樣的方式抓取咪咕音樂(http://m.music.migu.cn)作成咪咕音樂腳本,咪咕音樂更容易爬取

命令行主界面

主界面的主要功能就是以表格的方式顯示搜索到的音樂和以序號的方式下載音樂

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("文件寫入出錯:", err)
            return None

    def main(self):
        print('請輸入須要下載的歌曲或者歌手:')
        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(['序號', '歌手', '下載', '歌名'])
        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 退出:')
            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()

總結

音樂聚合下載器最重要的部分仍是爬蟲抓取各個音樂網站的數據,命令行的方式則省去了畫 GUI 的工做。

相關文章
相關標籤/搜索