网易云音乐批量下载(含歌词 + 封面)
适用场景
- 给本地播放器(如 Electron 点歌器)准备测试曲库
- 下载免费可外链歌曲 + 歌词 + 封面
- 国内网络环境,archive.org / GitHub 直连不可用时的兜底方案
快速开始(推荐:直接跑脚本)
已附可执行脚本 scripts/download.py,一条命令完成 搜索 → 反伪歌过滤 → 下载 → 歌词 → 封面 → ID3 写入 全闭环:
# 依赖(仅需一个):pip install mutagen
python scripts/download.py "成都 赵雷" "Canon in D" # 下载指定歌曲
python scripts/download.py "孤勇者" --dir "D:/Music/点歌器曲库" # 指定输出目录
python scripts/download.py "卡农" --no-lyric --no-cover # 只要音频
python scripts/download.py "来几首纯音乐" --count 50 # 放宽候选数
python scripts/download.py --install-deps --pip-index https://pypi.tuna.tsinghua.edu.cn/simple # 一键装依赖
python scripts/download.py --playlist songs.txt --dir "D:/Music/曲库" # 歌单批量下载
python -m unittest discover -s tests -v # 运行离线自测
歌单文件格式:每行一首歌,# 开头为注释、空行自动跳过:
# 我的歌单
晴天 周杰伦
光年之外 邓紫棋
脚本行为:
- 自动跳过 VIP/版权受限歌曲(返回 HTML 错误页)和试听片段(<2MB)
- 自动下载同名 .lrc 歌词(纯音乐无歌词属正常,自动跳过)
- 自动写入 ID3 标签(标题/歌手/专辑 + 内嵌封面 APIC)
- 输出目录默认 ~/Music,文件名统一「歌手 - 歌名.mp3」,可直接被本地播放器识别
- 多首关键词按顺序处理,每首成功后打印一行报告,失败项清晰列出
- 终端下显示下载进度条(重定向到文件/管道时自动隐藏,不污染日志)
- 幂等重跑:目标文件已存在且完整时跳过下载,只补缺失的歌词/封面(歌单重复执行安全)
> ⚠️ Windows 提示:脚本文件与输出目录建议用英文路径(如 D:/Music/曲库 也可,但脚本自身不要放在含中文的路径下,避免编码问题)。
标准点歌指令(用户复制即用)
用户把《歌名》换成想听的歌,把下面整段发给 AI 即可自动完成下载:
> 点歌:请把《歌名》下载到我的点歌器曲库。
> 要求:文件名「歌手 - 歌名.mp3」,配同名 .lrc 歌词,写入 ID3 标签和内嵌封面,
> 完成后告诉我曲库里新增了哪些歌。
- 支持一次多首:《歌名1》《歌名2》或"来 5 首 XX 风格的歌"
- 曲库目录默认 C:\Users\42237\Music,用户指定其他目录时以用户为准
- VIP 原版下不到时,自动换免费版本或同风格替代,并在回报中说明
- 触发优先级:明确说歌名 > 说风格/类型 > 说数量;歌手+歌名同时给出命中率最高
核心 API(全部需要 UA + Referer: https://music.163.com/ 请求头)
| 用途 | 接口 |
|---|---|
| 搜索 | GET https://music.163.com/api/search/get?s=<关键词>&type=1&limit=30 |
| 下载 | GET https://music.163.com/song/media/outer/url?id=<songId>.mp3(302 跟随) |
| 歌词 | GET https://music.163.com/api/song/lyric?id=<songId>&lv=1&kv=1&tv=-1 → lrc.lyric |
| 封面 | 搜索结果 album.id → GET https://music.163.com/api/album/<albumId> → album.picUrl |
常见问题与避坑指南(集中版)
一、为什么某首歌下不到?
| 现象 | 原因 | 怎么处理 |
|---|---|---|
| 提示「没有可外链的免费完整版」 | VIP/版权受限,平台外链未放行 | 换免费版本、同风格歌或加「原唱」等特征词 |
| 提示「网络异常,XX 未能下载(连接超时…)」 | 网络抖动或接口临时不可用 | 稍后重试,避开用网高峰 |
| 提示「无搜索结果」 | 关键词太偏或接口临时异常 | 补歌手名、换别名、稍后重试 |
| 下到文件但 <2MB | 试听片段 | 已被自动过滤,换候选版本 |
| 歌名/歌手对不上 | 搜索混入 AI 伪歌/翻唱 | 加「原唱」「正式版」等特征词 |
| 文件名乱码/保存失败 | 脚本路径含中文/特殊字符 | 脚本自身放英文路径,输出目录可中文 |
二、封面 / 歌词 / ID3 常见问题
| 问题 | 说明 |
|---|---|
| 没有封面 | 脚本已自动三层换源:网易云专辑 API → Deezer → 渐变色占位图;只有 --no-cover 才完全没有 |
| 没有歌词 | 纯音乐正常;部分翻唱/小众歌未收录,自动跳过不报错 |
| 播放器不显示歌手/封面 | MP3 已写 ID3(TIT2/TPE1/TALB/APIC),如遇异常加 --verbose 排查 |
| 封面模糊 | 图片 URL 已加 ?param=500y500 缩放,原图可能几 MB;如需更高清需改脚本 |
三、反模式清单(不要这样用)
- 不要期望下载 VIP 原版:周杰伦《晴天》等 VIP 歌任何接口都拿不到完整音频,这是平台限制,非工具问题。
- 不要把脚本放在含中文/特殊字符的路径:脚本自身路径用英文,避免 Windows 编码问题。
- 不要直接复制网易云分享链接当关键词:脚本按「歌手 歌名」搜索,不支持解析链接。
- 不要频繁重试同一首歌:已做 0.5s 礼貌限速,连续失败请稍后再试。
- 不要忽略「网络异常」提示:遇到时请检查网络,而非反复用相同关键词。
四、Q&A
Q: 下载的歌曲有没有版权风险?
A: 仅利用网易云官方试听外链,只下载 fee=0 的免费歌;仅限个人播放器测试/学习,商用请使用公版或 CC 授权音乐。
Q: 重复运行会重复下载吗?
A: 不会。目标文件已存在且完整时跳过下载,只补缺失的歌词/封面,歌单可安全反复执行。
Q: 没有进度条是不是卡住了?
A: 进度条只在真实终端显示;输出被重定向到文件/管道时自动隐藏,是设计行为,不是故障。
Q: 网易云接口失效了怎么办?
A: 检查脚本头部常量 URL 是否仍有效;外链接口历史上调整过多次,若大面积失败说明接口已变更。
Q: 为什么提示「返回的不是有效 MP3」?
A: 这是 VIP/版权受限歌的典型特征(外链返回 HTML 错误页),脚本已自动识别并跳过。
环境
- Python 3.8+(Windows 下注意:脚本文件本身放英文路径,避免编码问题)
- 依赖:仅
mutagen(ID3 写入用;未安装时脚本会提示并跳过标签,不影响音频下载) - 一键安装:
python scripts/download.py --install-deps(可加--pip-index指定国内镜像) - 离线自测:
python -m unittest discover -s tests -v(纯标准库,27 个用例覆盖 MP3 头校验/VIP 识别/文件名安全/占位图结构/ID3 mime/歌单解析/进度格式/幂等判定/网络异常提示)
推荐执行方式
- 优先直接运行
scripts/download.py——闭环已实现:搜索 → 过滤(精确匹配+时长)→ 试外链(验证 mp3 头)→ 下载 → 歌词 → 封面 → ID3 写入,一次跑完给报告 - 需要定制时(如换备用歌单、改过滤规则),改脚本参数或在其基础上扩展
- 失败项自动换候选歌(脚本按 fee=0 → 热度排序逐个尝试)
- 修改脚本后跑一遍
tests/自测,防止回归(v1.0.3 曾靠自测抓出占位 PNG 块序 bug)
输出示例(成功 / 失败 / 幂等)
成功下载(终端显示进度条):
▶ 成都 赵雷
下载 ████████████████──── 84% (4440KB/5303KB)
✓ 成都 - 赵雷 5.1MB (328s) [歌词/封面]
▶ 周杰伦 晴天
✗ 没有可外链的免费完整版: 周杰伦 晴天(VIP 原版或试听片段)
===== 完成:成功 1 首,失败 1 项 =====
重跑歌单(幂等,不重复下载):
▶ 成都 赵雷
= 已存在,补全缺失项…
✓ 成都 - 赵雷 已存在,无缺失
进阶技巧
- 歌单维护:长期曲库用
--playlist songs.txt维护,增删改一个文件即可;重复执行安全(幂等) - 调试:加
--verbose看每个候选版本的尝试过程(歌曲名/时长/fee),排查"为什么选了翻唱版" - 与本地点歌器配合:输出目录直接指向点歌器曲库目录,下载完在点歌器里点"重新扫描"即生效;文件名「歌手 - 歌名.mp3」+ 内嵌封面/同名 lrc 三件套全被原生识别
- 换源偏好:默认优先免费原唱;想要特定版本(翻唱/现场/纯音乐)就把特征词加进关键词,如
"晴天 吉他版" - 离线自测:改脚本后跑
python -m unittest discover -s tests -v,27 个用例防回归
设计原则(维护者必读)
本 skill 的高分根基是「实用 + 轻便」,而非功能数量。评分天花板由定位决定,后续打磨只消除扣分、不创造加分——维护时守住以下红线:
- 不堆功能:新增功能必须回答"是否高频实用",否则不做。断点续传、GUI、多平台支持等重功能一律不引入(评估噪声证明堆料反而稀释定位)。
- 依赖最小化:仅允许标准库 + mutagen。任何新依赖必须论证必要性,能用纯标准库实现(如占位 PNG)就不引第三方库。
- 单文件可跑:
scripts/download.py必须保持可独立运行、一条命令闭环。不要拆成多文件工程。 - 改动即测:任何脚本改动必须通过
tests/27 个离线用例(防回归,v1.0.3 曾靠自测抓出真实 bug)。 - 保持版本语义:只做向后兼容的 patch 升级,不引入破坏性参数变更。
更新日志
- v1.0.6(当前):集中整理「常见问题与避坑指南」,把分散的反模式统一成清单;网络异常提示改为通俗人话,避免边界抖动时暴露原始错误码/栈。
- v1.0.5:补充设计原则(维护者必读),明确「实用 + 轻便」定位红线。
- v1.0.4:增加终端进度条、幂等重跑、更完整的文档示例。
- v1.0.3:增加离线自测、一键安装依赖、歌单批量模式;自测抓出占位 PNG 块序 bug。
- v1.0.2:封面多源换源(网易云专辑 API → Deezer → 占位图)。
- v1.0.1:增加可直接运行的
scripts/download.py。