# 导入所需模块
import random # 生成随机数,用于请求间隔
import time # 时间相关操作,生成时间戳
import hashlib # 哈希库,用于生成MD5签名
import requests # HTTP请求库
import re # 正则表达式,用于文本匹配
import os # 操作系统接口,处理文件路径
import sys # 系统相关功能,用于退出程序
# 榜单选项配置
rank_options = [
{"name": "酷狗飙升榜", "id": "6666"},
{"name": "酷狗TOP500", "id": "8888"},
{"name": "蜂鸟流行音乐榜", "id": "59703"},
{"name": "抖音热歌榜", "id": "52144"},
{"name": "快手热歌榜", "id": "52767"},
{"name": "DJ热歌榜", "id": "24971"},
{"name": "内地榜", "id": "31308"}
]
# 用户交互界面
print("请选择要下载的榜单")
print("0.退出程序")
# 遍历显示榜单选项(从1开始编号)
for index, rank in enumerate(rank_options, 1):
print(f"{index}.{rank['name']}")
# 输入验证循环
while True:
choice = input("请输入选择(0-7):")
if choice in ['0', '1', '2', '3', '4', '5', '6', '7']:
choice = int(choice)
break
print("输入错误,请重新输入!")
# 退出程序处理
if choice == 0:
sys.exit()
# 获取选择的榜单信息
selected_rank = rank_options[choice - 1]
rank_id = selected_rank['id']
print(f"您选择的是:{selected_rank['name']}")
# 设置下载目录并创建(如果不存在)
MOVIE_DIR = r"D:\Music\酷狗音乐"
os.makedirs(MOVIE_DIR, exist_ok=True) # exist_ok=True表示目录已存在时不报错
# 请求头配置
headers = {
'referer': 'https://www.kugou.com/yy/html/rank.html',
'cookie': '您的cookie信息',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36 Edg/134.0.0.0'
}
max_retries = 3 # 最大重试次数
pages = 1 # 起始页码
# 主循环:处理多页数据
while True:
# 构造榜单页面URL
rank_url = f'https://www.kugou.com/yy/rank/home/{pages}-{rank_id}.html?from=rank'
# 请求榜单页面
rank_res = requests.get(rank_url, headers=headers)
# 使用正则表达式提取歌曲eid
data_eid = re.findall('data-eid="(.*?)">', rank_res.text)
if not data_eid: # 没有数据时终止循环
break
# 遍历每个歌曲eid
for eid in data_eid:
# 生成时间戳(毫秒级)
Time = int(time.time() * 1000)
# 构造签名参数列表
s = [
"NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt",
"appid=1014",
f"clienttime={Time}",
"clientver=20000",
"dfid=3x76o93Ae7Fa4QPjcd4TnMat",
f"encode_album_audio_id={eid}",
"mid=9722897a4e3934b485c53fac3d282c3b",
"platid=4",
"srcappid=2919",
"token=7bd6e28f3763a7f3762a5eaa39b8e44fa8120fd1f6e35fea7b515d5a9fbf32d0",
"userid=2190417243",
"uuid=9722897a4e3934b485c53fac3d282c3b",
"NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt"
]
# 生成MD5签名
md5 = hashlib.md5()
sign_str = ''.join(s) # 拼接字符串
md5.update(sign_str.encode('utf-8')) # 编码并计算哈希
signature = md5.hexdigest() # 获取16进制哈希值
# 构造API请求URL
api_url = f'https://wwwapi.kugou.com/play/songinfo?srcappid=2919&clientver=20000&clienttime={Time}&mid=9722897a4e3934b485c53fac3d282c3b&uuid=9722897a4e3934b485c53fac3d282c3b&dfid=3x76o93Ae7Fa4QPjcd4TnMat&appid=1014&platid=4&encode_album_audio_id={eid}&token=7bd6e28f3763a7f3762a5eaa39b8e44fa8120fd1f6e35fea7b515d5a9fbf32d0&userid=2190417243&signature={signature}'
# 请求歌曲信息API
api_res = requests.get(api_url, headers=headers)
# 处理歌曲信息
audio_name = api_res.json()['data']['audio_name'] # 获取歌曲标题
clean_title = re.sub(r'[\\/*?:"<>|]', "", audio_name) # 清理非法文件名字符
play_url = api_res.json()['data']['play_url'] # 获取播放地址
# 检查必要数据是否存在
if not clean_title or not play_url:
break
# 构造文件路径
file_path = os.path.join(MOVIE_DIR, f"{clean_title}.mp3")
# 检查文件是否已存在
if os.path.exists(file_path):
print(f"歌曲文件已存在: {clean_title} --- 跳过下载")
continue
# 下载重试机制
success = False
for attempt in range(max_retries):
try:
# 下载音频文件
audio_data = requests.get(play_url, headers=headers, timeout=20).content
# 有效性检查(文件大小超过1KB)
if len(audio_data) > 1024:
# 写入文件
with open(file_path, 'wb') as audio_file:
audio_file.write(audio_data)
# 二次验证文件大小
if os.path.getsize(file_path) > 1024:
success = True
break
print(f"第{attempt + 1}次下载不完整,重新尝试...")
else:
print(f"第{attempt + 1}次下载失败,重新尝试...")
except Exception as e:
print(f"第{attempt + 1}次下载出错: {str(e)}")
# 重试间隔
time.sleep(2)
# 下载结果处理
if success:
print(f"成功下载: {clean_title}")
else:
print(f"下载失败: {clean_title}")
continue
# 随机延时(5-15秒)防止被封禁
time.sleep(random.uniform(5, 15))
# 翻页处理
pages += 1
05-06
1758

10-10
1148
