效果圖

代碼中用到了
Crypto
子產品,Windows安裝時會報錯,① 建議選擇對應解釋器的版本搜尋安裝依賴
.whl
字尾的依賴封包件,找到之後直接
pip install XXX.whl
就可以了,在文章後面我提供了百度網盤連接配接,可以下載下傳安裝依賴、源碼以及打包後的exe檔案,我下載下傳的是python3.6的依賴包,② window下安裝
pycryptodome
子產品也可以,
pip install pycryptodome
,但是由于這個子產品暫時沒有更新維護,安裝了有時候無法使用,python3.6和python3.7已經親測無法使用,③ Linux不需要考慮這個編譯環境問題,可以直接安裝
Crypto
即可
from copy import deepcopy
import requests, json, base64
from binascii import hexlify
from Crypto.Cipher import AES
from tkinter import *
from tkinter.filedialog import askdirectory
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()
self.detail_list = []
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']
# 搜尋到的所有歌曲資訊(id,name,singer)
detail_list = []
i = 1
for song in songs:
song_id, song_name, singer, alia = song['id'], song['name'], song['ar'][0]['name'], song['al']['name']
print(song_id, song_name, singer, alia)
item = {}
item['num'] = i
item['song_id'] = song_id
item['song_name'] = song_name
item['author_name'] = singer
detail_list.append(item)
i += 1
# 将得到的歌曲詳細資訊初始化,友善後續調用
self.detail_list += detail_list
# def __str__(self):
# return str(self.detail_list)
def song_load(new_detail_list, num):
num = int(num)
# GUI文本框輸入的資訊
text.insert(END, '正在下載下傳...')
text.see(END)
text.update()
# 根據輸入歌曲編号,在清單中取出對應的歌曲資訊
# 組裝url
item = new_detail_list[num - 1]
song_id = item['song_id']
song_name = item['song_name']
singer = item['author_name']
song_url = 'http://music.163.com/song/media/outer/url?id={}.mp3'.format(song_id)
# 判斷是否選擇下載下傳路徑
print(selects_path)
if selects_path:
# 拼接路徑
os.makedirs('{}/music_netease'.format(selects_path), exist_ok=True)
path = '{}/music_netease/{}.mp3'.format(selects_path, song_name)
else:
os.makedirs('music_netease', exist_ok=True)
path = 'music_netease/{}.mp3'.format(song_name)
print(selects_path)
# path = 'music_netease/{}.mp3'.format(song_name)
# path = '{}/music_netease/{}.mp3'.format(select_path,song_name)
print(path)
# 下載下傳路徑顯示
text.insert(END, path)
text.see(END)
text.update()
# 顯示資料到文本框
text.insert(END, '歌曲:{}, 歌手: {},正在下載下傳...'.format(song_name, singer))
text.see(END)
text.update()
urlretrieve(song_url, path)
text.insert(END, '下載下傳完畢: {},請試聽!'.format(song_name))
text.see(END)
text.update()
if __name__ == '__main__':
selects_path = None
# 搜尋歌曲名字
def get_music_name():
# 擷取輸入框輸入的歌曲名字
name = entry.get()
d = search()
d.search_song(name)
detail_list = d.detail_list
global new_detail_list
new_detail_list = []
for i in detail_list:
new_detail_list.append(deepcopy(i))
i.pop('song_id')
text.insert(END, i)
text.see(END)
text.update()
def load_song():
# 擷取下載下傳歌曲編号
num = entry1.get()
# 下載下傳歌曲
song_load(new_detail_list, num)
def select_path():
def selectPath():
path_ = askdirectory()
# print(path_)
path.set(path_)
# print('*'*100)
global selects_path
selects_path = path_
print(path_)
root1.destroy()
return path_
root1 = Tk()
root1.geometry('+550+300')
path = StringVar()
Label(root1, text="目标路徑:").grid(row=0, column=0)
Entry(root1, textvariable=path).grid(row=0, column=1)
Button(root1, text="路徑選擇", command=selectPath).grid(row=0, column=2)
root1.mainloop()
# 搭建界面
# 建立界面
root = Tk()
# 添加标題
root.title('網易雲音樂')
# 設定視窗大小 x 小寫x連,不能用乘号 後面兩位是x,y坐标,固定初始位置
root.geometry('545x460+400+150')
# 設定圖形界面的大小鎖定,禁止改變
root.resizable(width=False, height=False)
# 标簽控件
label = Label(root, text='請輸入下載下傳的歌曲:', font=('華文行楷', 20))
# 标簽定位 grid 網格式定位
label.grid(row=0, column=0, sticky=W) # 預設 row=0,column=0
# 輸入框
entry = Entry(root, font=('隸書', 20))
entry.grid(row=0, column=1, sticky=W)
# command 點選觸發方法 搜尋歌曲
button2 = Button(root, text='搜 索', font=('隸書', 15), command=get_music_name)
# 定位 sticky 對齊方式 W E N S 東南西北
button2.grid(row=1, column=1, sticky=E)
# command 點選觸發方法 檔案儲存路徑選擇
button3 = Button(root, text='下載下傳路徑', font=('隸書', 15), command=select_path)
# 定位 sticky 對齊方式 W E N S 東南西北
button3.grid(row=1, column=0, sticky=W)
# 清單框
text = Listbox(root, font=('楷書', 12), width=68, heigh=18)
# 定位 columnspan 元件橫跨的列數
text.grid(row=2, columnspan=2)
label1 = Label(root, text='輸入下載下傳歌曲編号:', font=('華文行楷', 20))
label1.grid(row=3, column=0)
entry1 = Entry(root, font=('隸書', 20))
entry1.grid(row=3, column=1, sticky=E)
# 點選按鈕
button = Button(root, text='開始下載下傳', font=('隸書', 15), command=load_song)
# 定位 sticky 對齊方式 W E N S 東南西北
button.grid(row=4, column=0, sticky=W)
button1 = Button(root, text='退出程式', font=('隸書', 15), command=root.quit)
button1.grid(row=4, column=1, sticky=E)
# 顯示界面
root.mainloop()
一些細節問題請檢視本人部落格另外兩篇關于網易雲下載下傳的文章
python網易雲音樂下載下傳打包exe檔案,Windows可運作
python網易雲音樂下載下傳_GUI圖形化界面
源碼、安裝依賴檔案以及打包後的exe檔案連接配接位址(永久有效)
https://pan.baidu.com/s/1OmND7lblnkxypIF4dTLy_Q