網易雲10萬+音樂竟然能用Python一鍵下載!


如果你常聽音樂的話,肯定繞不開網易雲,作為一款有情懷的音樂 App,我對網易雲也是喜愛有加。雖然說現在都已經是 5G 時代了,大家的手機流量都綽綽有余,但在線播放還是不如本地存着音樂文件靠譜,今天我們就用 Python 來一鍵下載網易雲音樂樂庫。

先來看下最終的效果。

其實下載音樂不難,只需要獲取到音樂文件播放的地址就可以通過文件流讀取的方式直接下載下來。那么問題就轉化為如何獲取音樂文件的播放地址了。\



很多人學習python,不知道從何學起。
很多人學習python,掌握了基本語法過后,不知道在哪里尋找案例上手。
很多已經做案例的人,卻不知道如何去學習更加高深的知識。
那么針對這三類人,我給大家提供一個好的學習平台,免費領取視頻教程,電子書籍,以及課程的源代碼!
QQ群:609616831


榜單分析

我們可以打開網易雲排行榜 https://music.163.com/#/discover/toplist?id=19723756,仔細分析我們發現該網頁左邊一列全是排行榜,每個排行榜都對應這不同的排行榜 ID,具體 ID 是多少,直接調開開發者工具即可清晰的看到。

由上圖我們可以看到榜單是放在一個 class='f-cb' 的 ul 列表里面的,所以只需要獲取到該 ul 列表的 li 標簽即可。而對於每一個 li 標簽來說,其 data-res-id 屬性則是榜單 id,而榜單名稱則是屬於該 li 標簽下的 div 中 class='name' 的 p 標簽下的 a 標簽的內容。因此我們獲取到 li 標簽的集合之后,遍歷該集合依次取出榜單 id 和榜單名稱即可。\

於是我們有了下面的函數,獲取所有的榜單,該函數返回值是一個字典,key 為 榜單 id,值為榜單名稱。

url = 'https://music.163.com/discover/toplist'
hd = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36'
}

def get_topic_ids():
    r = requests.get(url, headers=hd)
    html = etree.HTML(r.text)
    nodes = html.xpath("//ul[@class='f-cb']/li")
    logger.info('{}  {}'.format('榜單 ID', '榜單名稱'))
    ans = dict()
    for node in nodes:
        id = node.xpath('./@data-res-id')[0]
        name = node.xpath("./div/p[@class='name']/a/text()")[0]
        ans[id] = name
        logger.info('{}  {}'.format(id, name))
    return ans

歌曲分析

上面我們獲取到了所有的榜單數據,那么針對單個榜單來說,就是要獲取其下的所有歌曲了。

分析頁面原屬可知,歌曲列表是在一個 table 中的,但是通過 requests.get(url,headers=hd) 方式獲取返回的網頁文本內容的話,貌似是獲取不到 table 元素的。於是我們將其返回值輸出后做了仔細分析,發現歌曲是在 class="f-hide" 的 ul 標簽中。與獲取榜單類似,同樣需要先獲取所有的 li 標簽,然后在逐個獲取歌曲 id 和歌曲 name 就可以了。

def get_topic_songs(topic_id, topic_name):
    params = {
        'id': topic_id
    }
    r = requests.get(url, params=params, headers=hd)
    html = etree.HTML(r.text)
    nodes = html.xpath("//ul[@class='f-hide']/li")
    ans = dict()
    logger.info('{} 榜單 {} 共有歌曲 {} 首 {}'.format('*' * 10, topic_name, len(nodes), '*' * 10))
    for node in nodes:
        id = node.xpath('./a/@href')[0].split('=')[1]
        name = node.xpath('./a/text()')[0]
        ans[id] = name
        logger.info('{}  {}'.format(id, name))

    return ans

同樣該函數返回一個字典,key 為歌曲 id,value 為歌曲名稱。

下載歌曲

我們還需要一個下載歌曲的函數,該函數接收歌曲 id,然后以文件流的形式直接讀取到本地。

def down_song_by_song_id_name(id, name):
    if not os.path.exists(download_dir):
        os.mkdir(download_dir)
    url = 'http://music.163.com/song/media/outer/url?id={}.mp3'
    r = requests.get(url.format(id), headers=hd)
    is_fail = False
    try:
        with open(download_dir + name + '.mp3', 'wb') as f:
            f.write(r.content)
    except:
        is_fail = True
        logger.info("%s 下載出錯" % name)
    if (not is_fail):
        logger.info("%s 下載完成" % name)

最后將所有的操作組合到 main 函數中,作為程序的入口函數。

def main():
    ids = get_topic_ids()
    while True:
        print('')
        logger.info('輸入 Q 退出程序')
        logger.info('輸入 A 下載全部榜單歌曲')
        logger.info('輸入榜單 Id 下載當前榜單歌曲')

        id = input('請輸入:')

        if str(id) == 'Q':
            break
        elif str(id) == 'A':
            for id in ids:
                down_song_by_topic_id(id, ids[id])
        else:
            print('')
            ans = get_topic_songs(id, ids[id])
            print('')
            logger.info('輸入 Q 退出程序')
            logger.info('輸入 A 下載全部歌曲')
            logger.info('輸入歌曲 Id 下載當前歌曲')
            id = input('請輸入:')
            if str(id) == 'Q':
                break
            elif id == 'A':
                down_song_by_topic_id(id, ans[id])
            else:
                down_song_by_song_id_name(id, ans[id])

if __name__ == "__main__":
    main()

總結

今天我們以網易雲網頁版為數據源來下載音樂文件,其中下載操作是最簡單的,比較麻煩的是分析榜單 id 和獲取榜單下的歌曲列表,但榜單下的歌曲列表其實遠不止 10 條,而我們獲取歌曲的函數 get_topic_songs 每次只可以獲取 10 條歌曲,這是因為我們沒有在 headers 添加 cookie 導致的,因為只有登錄之后才會顯示所有的歌曲。小伙伴們可以登錄自己的賬戶然后添加 cookie 做下嘗試。

在這里還是要推薦下我自己建的Python學習群:609616831,群里都是學Python的,如果你想學或者正在學習Python ,歡迎你加入,大家都是軟件開發黨,不定期分享干貨(只有Python軟件開發相關的),包括我自己整理的一份2020最新的Python進階資料和零基礎教學,歡迎進階中和對Python感興趣的小伙伴加入!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM