七仔的博客

七仔的博客GithubPages分博

0%

Python 网易云音乐 歌单及MV下载器

通过网易云API,根据歌单的ID即可下载全部歌曲,如果歌曲绑定了MV将会同时下载MV

Python 网易云音乐 歌单及MV下载器

注:此程序仅用于学习和研究

图标

一、运行截图

主界面

二、介绍

输入网易云音乐的歌单URL即可下载歌曲及所关联的MV。(下载路径最后要有/)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
from tkinter import *
import requests
from bs4 import BeautifulSoup
import random, math
from Crypto.Cipher import AES
import base64
import codecs
import os
import urllib
from lxml import html
etree = html.etree


class Spider(object):
def __init__(self):
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0',
'Cookie':'_iuqxldmzr_=32; _ntes_nnid=8d4ef0883a3bcc9d3a2889b0bf36766a,1533782432391; _ntes_nuid=8d4ef0883a3bcc9d3a2889b0bf36766a; __utmc=94650624; WM_TID=GzmBlbRkRGQXeQiYuDVCfoEatU6VSsKC; playerid=19729878; __utma=94650624.1180067615.1533782433.1533816989.1533822858.9; __utmz=94650624.1533822858.9.7.utmcsr=cn.bing.com|utmccn=(referral)|utmcmd=referral|utmcct=/; WM_NI=S5gViyNVs14K%2BZoVerGK69gLlmtnH5NqzyHcCUY%2BiWm2ZaHATeI1gfsEnK%2BQ1jyP%2FROzbzDV0AyJHR4YQfBetXSRipyrYCFn%2BNdA%2FA8Mv80riS3cuMVJi%2BAFgCpXTiHBNHE%3D; WM_NIKE=9ca17ae2e6ffcda170e2e6ee84b674afedfbd3cd7d98b8e1d0f554f888a4abc76990b184badc4f89e7af8ece2af0fea7c3b92a91eba9b7ec738e8abdd2b741e986a1b7e87a8595fadae648b0b3bc8fcb3f8eafb69acb69818b97ccec5dafee9682cb4b98bb87d2e66eb19ba2acaa5bf3b6b7b1ae5a8da6ae9bc75ef49fb7abcb5af8879f87c16fb8889db3ec7cbbae97a4c566e992aca2ae4bfc93bad9b37aab8dfd84f8479696a7ccc44ea59dc0b9d7638c9e82a9c837e2a3; JSESSIONID-WYYY=sHwCKYJYxz6ODfURChA471BMF%5CSVf3%5CTc8Qcy9h9Whj6CfMxw4YWTMV7CIx5g6rqW8OBv04YGHwwq%2B%5CD1N61qknTP%2Fym%2BHJZ1ylSH1EabbQASc9ywIT8YvOr%2FpMgvmm1cbr2%2Bd6ssMYXuTlpOIrKqp%5C%2FM611EhmfAfU47%5CSQWAs%2BYzgY%3A1533828139236'
}

def __get_songs(self, name):
d = '{"hlpretag":"<span class=\\"s-fc7\\">","hlposttag":"</span>","s":"%s","type":"1","offset":"0","total":"true","limit":"30","csrf_token":""}' % name
wyy = WangYiYun(d) # 要搜索的歌曲名在这里
data = wyy.get_data()
url = 'https://music.163.com/weapi/cloudsearch/get/web?csrf_token='
response = requests.post(url, data=data, headers=self.headers).json()
return response['result']

def __get_mp3(self, id):
d = '{"ids":"[%s]","br":320000,"csrf_token":""}' % id
wyy = WangYiYun(d)
data = wyy.get_data()
url = 'https://music.163.com/weapi/song/enhance/player/url?csrf_token='
response = requests.post(url, data=data, headers=self.headers).json()
return response['data'][0]['url']

def __download_mp3(self, url, filename):
if os.path.exists(_path.get() + filename + '.mp3'):
return
if url is None:
print(filename + " haven't download")
return
"""下载mp3"""
abspath = os.path.abspath('.') # 获取绝对路径
os.chdir(abspath)
response = requests.get(url, headers=self.headers).content
path = _path.get() + filename
with open(_path.get() + filename + '.mp3', 'wb') as f:
f.write(response)
print('下载完毕,可以在%s 路径下查看' % path + '.mp3')

def __print_info(self, songs):
"""打印歌曲需要下载的歌曲信息"""
songs_list = []
for num, song in enumerate(songs):
print(num, '歌曲名字:', song['name'], '作者:', song['ar'][0]['name'])
songs_list.append((song['name'], song['id']))
return songs_list

def run(self):
while True:
name = input('请输入你需要下载的歌曲:')
songs = self.__get_songs(name)
if songs['songCount'] == 0:
print('没有搜到此歌曲,请换个关键字')
else:
songs = self.__print_info(songs['songs'])
num = input('请输入需要下载的歌曲,输入左边对应数字即可')
url = self.__get_mp3(songs[int(num)][1])
if not url:
print('歌曲需要收费,下载失败')
else:
filename = songs[int(num)][0]
self.__download_mp3(url, filename)
flag = input('如需继续可以按任意键进行搜歌,否则按0结束程序')
if flag == '0':
break
print(songs)
print(url)
print(songs[int(num)][1])
print('程序结束!')

def download_a_music(self, id, filename):
url = self.__get_mp3(id)
self.__download_mp3(url, filename)


class WangYiYun(object):
def __init__(self, d):
self.d = d
self.e = '010001'
self.f = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5a" \
"a76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46be" \
"e255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
self.g = "0CoJUm6Qyw8W8jud"
self.random_text = self.get_random_str()

# js中的a函数
def get_random_str(self):
str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
res = ''
for x in range(16):
index = math.floor(random.random() * len(str))
res += str[index]
return res

def aes_encrypt(self, text, key):
iv = '0102030405060708' # 偏移量
pad = 16 - len(text.encode()) % 16 # 使加密信息的长度为16的倍数,要不会报下面的错
# 长度是16的倍数还会报错,不能包含中文,要对他进行unicode编码
text = text + pad * chr(pad) # Input strings must be a multiple of 16 in length
encryptor = AES.new(key, AES.MODE_CBC, iv)
msg = base64.b64encode(encryptor.encrypt(text)) # 最后还需要使用base64进行加密
return msg

# ras加密
def rsa_encrypt(self, value, text, modulus):
text = text[::-1]
rs = int(codecs.encode(text.encode('utf-8'), 'hex_codec'), 16) ** int(value, 16) % int(modulus, 16)
return format(rs, 'x').zfill(256)

def get_data(self):
# 这个参数加密两次
params = self.aes_encrypt(self.d, self.g)
params = self.aes_encrypt(params.decode('utf-8'), self.random_text)
enc_sec_key = self.rsa_encrypt(self.e, self.random_text, self.f)
return {
'params': params,
'encSecKey': enc_sec_key
}


class CloudMusicMV(object):
headers = {
'Host': 'music.163.com',
'Referer': 'https://music.163.com/',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0'
}

def get_mv(self, url, file_name):
if os.path.exists(_path.get() + file_name + '.mp4'): return
headers = {
'User - Agent': 'Mozilla / 5.0(Windows NT 6.1;WOW64) AppleWebKit / 537.36(KHTML, like Gecko) Chrome / 55.0.2883.87 Safari / 537.36'
}
req = requests.get(url, headers=headers)
if not os.path.exists(_path.get()):
os.makedirs(_path.get())
os.chdir(_path.get())
with open(file_name+'.mp4', 'wb') as file:
file.write(req.content)
file.close()
print(file_name+' download ok')

def get_msg(self, id):
req = requests.get('http://music.163.com/mv?id=' + id, headers=self.headers)
html = etree.HTML(req.text)
file_name = html.xpath('//a[@id="j-sharedata"]/@data-name')[0]
url = html.xpath('//meta[@property="og:video"]/@content')[0]
url = urllib.parse.unquote(url) # url解码
print(url)
return url, file_name

def get_mv_id(self, song_id):
req = requests.get('https://music.163.com/song?id=' + song_id, headers=self.headers)
mv_ids = etree.HTML(req.text).xpath('//a[@title="播放mv"]/@href')
return mv_ids


def download():
url = entry.get()
new_url = url.replace('/#', '')

header = {
'Host': 'music.163.com',
'Referer': 'https://music.163.com/',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0'
}

res = requests.get(new_url, headers=header).text

r = BeautifulSoup(res, "html.parser")
music_dict = {}
result = r.find('ul', {'class', 'f-hide'}).find_all('a')
spider = Spider()
cloudMusicMV = CloudMusicMV()
for music in result:
music_id = music.get('href').strip('/song?id=')
music_name = music.text
music_dict[music_id] = music_name
for song_id in music_dict:
msg["text"] = "正在下载音乐:%s" % music_dict[song_id]
msg.update()
# 添加数据
spider.download_a_music(song_id, music_dict[song_id])
text.insert(END, "音乐下载完成:%s" % music_dict[song_id])
text.see(END)
text.update()
mv_ids = cloudMusicMV.get_mv_id(song_id)
if len(mv_ids) is not 0:
msg["text"] = "正在下载MV:%s" % music_dict[song_id]
msg.update()
url, file_name = cloudMusicMV.get_msg(mv_ids[0][7:])
cloudMusicMV.get_mv(url, file_name)
text.insert(END, "MV下载完成:%s" % music_dict[song_id])
text.see(END)
text.update()


root = Tk()
root.title("网易云音乐及MV整合下载器——七仔")
root.geometry("410x650+550+100")
label = Label(root, text="歌单URL", font=('宋体', 12))
label.grid()
entry = Entry(root, font=('微软雅黑', 12))
entry.grid(row=0, column=1, sticky=E+W)
label = Label(root, text="下载路径", font=('宋体', 12))
label.grid(row=1, column=0)
_path = Entry(root, font=('微软雅黑', 12))
_path.grid(row=1, column=1, sticky=E+W)
msg = Label(root, text="未进行下载", font=('宋体', 12))
msg.grid(row=2, columnspan=2)
text = Listbox(root, font=("微软雅黑", 12), width=45, height=23)
text.grid(row=3, columnspan=2)
button = Button(root, text="开始下载", font=("微软雅黑", 10), command=download)
button.grid(row=4, column=0)
button1 = Button(root, text="退出", font=("微软雅黑", 10), command=root.quit)
button1.grid(row=4, column=1)
msgs = Label(root, text="此系统仅供个人学习、研究之用,禁止非法传播或用于商业用途,", font=('宋体', 8))
msgs.grid(row=5, columnspan=2)
msgs = Label(root, text="请在下载24小时内删除", font=('宋体', 8))
msgs.grid(row=6, columnspan=2)

entry.insert(0, 'https://music.163.com/#/playlist?id=2487763362')
_path.insert(0, 'E:\\my\\music\\J·Fla\\')

mainloop()

此为博主副博客,留言请去主博客,转载请注明出处:https://www.baby7blog.com/myBlog/6.html

欢迎关注我的其它发布渠道