网易云音乐越来越多歌曲成VIP了。。。(收获大批固定用户后,开始恰饭了)
利用python从缓存文件中获取MP3主要包括以下流程:
1、对缓存文件的数据和0xa3(163)进行异或(^)运算
2、用歌曲ID用网易云提供的API去获取歌曲信息
3、数据保存为mp3文件
1.缓存文件目录及文件类型
手机上网易云音乐的缓存目录在
netease/cloudmusic/Cache/Music1
可以看到包含2种类型的文件:IDX!(歌曲的一些属性,可以用记事本打开)和UC!(歌曲本身)文件
2.转换代码
# -*- coding:utf-8 -*-
import os
import re
import requests
UC_PATH = r'C:\Users\Petrichor\Desktop\music' # 缓存路径
MP3_PATH = r'C:\Users\Petrichor\Desktop\mp3' # 存放歌曲路径
class Transform():
def do_transform(self):
files = os.listdir(UC_PATH)
for file in files:
if file[-3:] == 'uc!': # 后缀uc!结尾为歌曲缓存
print(file)
uc_file = open(UC_PATH + file, mode='rb')
uc_content = uc_file.read()
mp3_content = bytearray()
for byte in uc_content:
byte ^= 0xa3
mp3_content.append(byte)
song_id = self.get_songid_by_filename(file)
song_name, singer_name = self.get_song_info(song_id)
a = re.findall(r'[^\*"/:?\\|<>]',song_name,re.S) #去除不能做文件名的字符
song_name = "".join(a)
mp3_file_name = MP3_PATH + '%s - %s.mp3' % (singer_name, song_name)
mp3_file = open(mp3_file_name, 'wb')
mp3_file.write(mp3_content)
uc_file.close()
mp3_file.close()
print('success %s' % mp3_file_name)
def get_songid_by_filename(self, file_name):
match_inst = re.match('\d*', file_name) # -前面的数字是歌曲ID,例:1347203552-320-0aa1
if match_inst:
return match_inst.group()
return ''
def get_song_info(self, song_id):
if not song_id:
return str(song_id), ''
try:
url = 'https://api.imjad.cn/cloudmusic/' # 请求url例子:https://api.imjad.cn/cloudmusic/?type=detail&id=1347203552
payload = {'type': 'detail', 'id': song_id}
reqs = requests.get(url, params=payload)
jsons = reqs.json()
song_name = jsons['songs'][0]['name']
singer = jsons['songs'][0]['ar'][0]['name']
return song_name, singer
except:
return str(song_id), ''
def check_path():
global UC_PATH, MP3_PATH
if not os.path.exists(UC_PATH):
print('缓存路径错误: %s' % UC_PATH)
return False
if not os.path.exists(MP3_PATH):
print('目标路径错误: %s' % MP3_PATH)
return False
if UC_PATH[-1] != '/': # 容错处理 防止绝对路径结尾不是/
UC_PATH += '/'
if MP3_PATH[-1] != '/':
MP3_PATH += '/'
return True
if __name__ == '__main__':
if not check_path():
exit()
transform = Transform()
transform.do_transform()
3.运行结果
代码主要参考https://blog.csdn.net/haha1fan/article/details/104464221
途中遇到的问题是像?
等字符在windows中是非法的,windows系统下文件名的非法字符有s = '*\/:?"<>|'
,这里采取过滤的方式。由于只有极少数的文件名是非法的,所以对所有歌名采取这一方式十分耗时。