通过官方的下载链接http://music.163.com/song/media/outer/url?id=歌曲id.mp3,
分析网页寻找歌曲id组装成song_url,urlretrieve(song_url, path)下载歌曲,
用pyinstaller将程序打包,脱离python环境Windows可运行
import requests, json, base64
from binascii import hexlify
# Windows安装注crypto有坑,新手建议先去Linux实现代码功能
from Crypto.Cipher import AES
from tkinter import *
# urlretrieve优点只用传入url和下载路径就可以实现下载
from urllib.request import urlretrieve
import os
class Encrypyed():
'''传入歌曲的ID,加密生成'params'、'encSecKey 返回'''
def __init__(self):
self.pub_key = '010001'
self.modulus = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'
self.nonce = '0CoJUm6Qyw8W8jud'
def create_secret_key(self, size):
return hexlify(os.urandom(size))[:16].decode('utf-8')
def aes_encrypt(self, text, key):
iv = '0102030405060708'
pad = 16 - len(text) % 16
text = text + pad * chr(pad)
encryptor = AES.new(key, AES.MODE_CBC, iv)
result = encryptor.encrypt(text)
result_str = base64.b64encode(result).decode('utf-8')
return result_str
def rsa_encrpt(self, text, pubKey, modulus):
text = text[::-1]
rs = pow(int(hexlify(text.encode('utf-8')), 16), int(pubKey, 16), int(modulus, 16))
return format(rs, 'x').zfill(256)
def work(self, ids, br=128000):
text = {'ids': [ids], 'br': br, 'csrf_token': ''}
text = json.dumps(text)
i = self.create_secret_key(16)
encText = self.aes_encrypt(text, self.nonce)
encText = self.aes_encrypt(encText, i)
encSecKey = self.rsa_encrpt(i, self.pub_key, self.modulus)
data = {'params': encText, 'encSecKey': encSecKey}
return data
def search(self, text):
text = json.dumps(text)
i = self.create_secret_key(16)
encText = self.aes_encrypt(text, self.nonce)
encText = self.aes_encrypt(encText, i)
encSecKey = self.rsa_encrpt(i, self.pub_key, self.modulus)
data = {'params': encText, 'encSecKey': encSecKey}
return data
class search():
'''跟歌单直接下载的不同之处,1.就是headers的referer
2.加密的text内容不一样!
3.搜索的URL也是不一样的
输入搜索内容,可以根据歌曲ID进行下载
'''
def __init__(self):
self.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',
'Host': 'music.163.com',
'Referer': 'http://music.163.com/search/'} ###!!注意,搜索跟歌单的不同之处!!
self.main_url = 'http://music.163.com/'
self.session = requests.Session()
self.session.headers = self.headers
self.ep = Encrypyed()
def search_song(self, search_content, search_type=1, limit=9):
"""
根据音乐名搜索
:params search_content: 音乐名
:params search_type: 不知
:params limit: 返回结果数量
return: 可以得到id 再进去歌曲具体的url
"""
url = 'http://music.163.com/weapi/cloudsearch/get/web?csrf_token='
text = {'s': search_content, 'type': search_type, 'offset': 0, 'sub': 'false', 'limit': limit}
data = self.ep.search(text)
resp = self.session.post(url, data=data)
result = resp.json()
if result['result']['songCount'] <= 0:
print('搜不到!!')
else:
songs = result['result']['songs']
# 默认下载搜索歌曲后第一首歌曲 for song in songs[:1]
for song in songs[:1]:
song_id, song_name, singer, alia = song['id'], song['name'], song['ar'][0]['name'], song['al']['name']
print(song_id, song_name, singer, alia)
# 获取音乐id和name
item = {}
item['song_id'] = song_id
item['song_name'] = song_name
# 下载音乐
song_load(item)
def song_load(item): # 下载歌曲
song_id = item['song_id']
song_name = item['song_name']
# 拼接下载url
song_url = 'http://music.163.com/song/media/outer/url?id={}.mp3'.format(song_id)
# 创建一个文件夹
# exist_ok=True 如果文件存在不会报错 不会继续创建
os.makedirs('music_netease', exist_ok=True)
path = 'music_netease\{}.mp3'.format(song_name)
# GUI图像画界面,显示数据到文本框
text.insert(END, '歌曲:{},正在下载...'.format(song_name))
# 文本框滚动
text.see(END)
# 更新
text.update()
# 下载歌曲
urlretrieve(song_url, path)
text.insert(END, '下载完毕: {},请试听!'.format(song_name))
text.see(END)
text.update()
if __name__ == '__main__':
# 搜索歌曲名字
def get_music_name():
# 获取输入框输入的歌曲名字
name = entry.get()
# 拼接url
# 搜索歌曲
song = search()
# 更具传入的歌名获取id
song.search_song(name)
# 下载歌曲
# song_load() # 在search_song()得到歌曲id后调用
# 搭建界面
# 创建界面
root = Tk()
# 添加标题
root.title('网易云音乐')
# 设置窗口大小 x 小写x连,不能用乘号 后面两位是x,y坐标,固定初始位置
root.geometry('550x430+400+200')
# 标签控件
label = Label(root, text='请输入下载的歌曲:', font=('华文行楷', 20))
# 标签定位 grid 网格式定位
label.grid() # 默认 row=0,column=0
# 输入框
entry = Entry(root, font=('隶书', 20))
# 定位 第0行 第1列
entry.grid(row=0, column=1)
# 列表框
text = Listbox(root, font=('楷书', 16), width=50, heigh=15)
# 定位 columnspan 组件横跨的列数
text.grid(row=1, columnspan=2)
# 点击按钮 command 点击按钮触发函数
button = Button(root, text='开始下载', font=('隶书', 15), command=get_music_name)
# 定位 sticky 对齐方式 W E N S 东南西北
button.grid(row=2, column=0, sticky=W)
# command 点击触发方法 command=root.quit 关闭窗口
button1 = Button(root, text='退出程序', font=('隶书', 15), command=root.quit)
# 定位 sticky 对齐方式 W E N S 东南西北
button1.grid(row=2, column=1, sticky=E)
# 显示界面
root.mainloop()
https://pan.baidu.com/s/1ajXctZyWJCP9bQjCnFxGOw
改进版:
python网易云音乐下载,可选择歌曲,下载路径