百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT知识 > 正文

Python 一键下载网易云音乐 10W+ 乐库

liuian 2025-04-26 19:24 8 浏览

如果你常听音乐的话,肯定绕不开网易云,作为一款有情怀的音乐 App,我对网易云也是喜爱有加。虽然说现在都已经是 5G 时代了,大家的手机流量都绰绰有余,但在线播放还是不如本地存着音乐文件靠谱,今天我们就用 Python 来一键下载网易云音乐乐库。

其实下载音乐不难,只需要获取到音乐文件播放的地址就可以通过文件流读取的方式直接下载下来。那么问题就转化为如何获取音乐文件的播放地址了。

榜单分析

我们可以打开网易云排行榜 https://music.163.com/#/discover/toplist?id=19723756,仔细分析我们发现该网页左边一列全是排行榜,每个排行榜都对应这不同的排行榜 ID,具体 ID 是多少,直接调开开发者工具即可清晰的看到。

由上图我们可以看到榜单是放在一个 class='f-cb'ul 列表里面的,所以只需要获取到该 ul 列表的 li 标签即可。而对于每一个 li 标签来说,其 data-res-id 属性则是榜单 id,而榜单名称则是属于该 li 标签下的 divclass='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 做下尝试。

相关推荐

深入解析 MySQL 8.0 JSON 相关函数:解锁数据存储的无限可能

引言在现代应用程序中,数据的存储和处理变得愈发复杂多样。MySQL8.0引入了丰富的JSON相关函数,为我们提供了更灵活的数据存储和检索方式。本文将深入探讨MySQL8.0中的JSON...

MySQL的Json类型个人用法详解(mysql json类型对应java什么类型)

前言虽然MySQL很早就添加了Json类型,但是在业务开发过程中还是很少设计带这种类型的表。少不代表没有,当真正要对Json类型进行特定查询,修改,插入和优化等操作时,却感觉一下子想不起那些函数怎么使...

MySQL的json查询之json_array(mysql json_search)

json_array顾名思义就是创建一个数组,实际的用法,我目前没有想到很好的使用场景。使用官方的例子说明一下吧。例一selectjson_array(1,2,3,4);json_array虽然单独...

头条创作挑战赛#一、LSTM 原理 长短期记忆网络

#头条创作挑战赛#一、LSTM原理长短期记忆网络(LongShort-TermMemory,LSTM)是一种特殊类型的循环神经网络(RNN),旨在解决传统RNN在处理长序列数据时面临的梯度...

TensorBoard最全使用教程:看这篇就够了

机器学习通常涉及在训练期间可视化和度量模型的性能。有许多工具可用于此任务。在本文中,我们将重点介绍TensorFlow的开源工具套件,称为TensorBoard,虽然他是TensorFlow...

图神经网络版本的Kolmogorov Arnold(KAN)代码实现和效果对比

本文约4600字,建议阅读10分钟本文介绍了图神经网络版本的对比。KolmogorovArnoldNetworks(KAN)最近作为MLP的替代而流行起来,KANs使用Kolmogorov-Ar...

kornia,一个实用的 Python 库!(python kkb_tools)

大家好,今天为大家分享一个实用的Python库-kornia。Github地址:https://github.com/kornia/kornia/Kornia是一个基于PyTorch的开源计算...

图像分割掩码标注转YOLO多边形标注

Ultralytics团队付出了巨大的努力,使创建自定义YOLO模型变得非常容易。但是,处理大型数据集仍然很痛苦。训练yolo分割模型需要数据集具有其特定格式,这可能与你从大型数据集中获得的...

[python] 向量检索库Faiss使用指北

Faiss是一个由facebook开发以用于高效相似性搜索和密集向量聚类的库。它能够在任意大小的向量集中进行搜索。它还包含用于评估和参数调整的支持代码。Faiss是用C++编写的,带有Python的完...

如何把未量化的 70B 大模型加载到笔记本电脑上运行?

并行运行70B大模型我们已经看到,量化已经成为在低端GPU(比如Colab、Kaggle等)上加载大型语言模型(LLMs)的最常见方法了,但这会降低准确性并增加幻觉现象。那如果你和你的朋友们...

ncnn+PPYOLOv2首次结合!全网最详细代码解读来了

编辑:好困LRS【新智元导读】今天给大家安利一个宝藏仓库miemiedetection,该仓库集合了PPYOLO、PPYOLOv2、PPYOLOE三个算法pytorch实现三合一,其中的PPYOL...

人工智能——图像识别(人工智能图像识别流程)

概述图像识别(ImageRecognition)是计算机视觉的核心任务之一,旨在通过算法让计算机理解图像内容,包括分类(识别物体类别)、检测(定位并识别多个物体)、分割(像素级识别)等,常见的应用场...

PyTorch 深度学习实战(15):Twin Delayed DDPG (TD3) 算法

在上一篇文章中,我们介绍了DeepDeterministicPolicyGradient(DDPG)算法,并使用它解决了Pendulum问题。本文将深入探讨TwinDelayed...

大模型中常用的注意力机制GQA详解以及Pytorch代码实现

分组查询注意力(GroupedQueryAttention)是一种在大型语言模型中的多查询注意力(MQA)和多头注意力(MHA)之间进行插值的方法,它的目标是在保持MQA速度的同时...

pytorch如何快速创建具有特殊意思的tensor张量?

专栏推荐正文我们通过值可以看到torch.empty并没有进行初始化创建tensor并进行随机初始化操作,常用rand/rand_like,randint正态分布(0,1)指定正态分布的均值还有方差i...