天天看点

python网易云音乐下载,可选择歌曲,下载路径

效果图

python网易云音乐下载,可选择歌曲,下载路径

代码中用到了

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