网易云音乐下载

"""
Author:tanxin
Date:2021-9-25
网易云音乐根据输入,得到歌曲列表,再根据输入编号下载指定歌曲。
"""
import base64
import binascii
import json
import random
import string
from urllib import parse
import requests
from Crypto.Cipher import AES
from fake_useragent import UserAgent


# 从a-z,A-Z,0-9中随机获取16位字符
def get_random():
    random_str = ''.join(random.sample(string.ascii_letters + string.digits, 16))
    return random_str


# AES加密要求加密的文本长度必须是16的倍数,密钥的长度固定只能为16,24或32位,因此我们采取统一转换为16位的方法
def len_change(text):
    pad = 16 - len(text) % 16
    text = text + pad * chr(pad)
    text = text.encode("utf-8")
    return text


# AES加密方法
def aes(text, key):
    # 首先对加密的内容进行位数补全,然后使用 CBC 模式进行加密
    iv = b'0102030405060708'
    text = len_change(text)
    cipher = AES.new(key.encode(), AES.MODE_CBC, iv)
    encrypted = cipher.encrypt(text)
    encrypt = base64.b64encode(encrypted).decode()
    return encrypt


# js中的 b 函数,调用两次 AES 加密
# text 为需要加密的文本, str 为生成的16位随机数
def b(text, str):
    first_data = aes(text, '0CoJUm6Qyw8W8jud')
    second_data = aes(first_data, str)
    return second_data


# 这就是那个巨坑的 c 函数
def c(text):
    e = '010001'
    f = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'
    text = text[::-1]
    result = pow(int(binascii.hexlify(text.encode()), 16), int(e, 16), int(f, 16))
    return format(result, 'x').zfill(131)


# 获取最终的参数 params 和 encSecKey 的方法
def get_final_param(text, str):
    params = b(text, str)
    encSecKey = c(str)
    return {'params': params, 'encSecKey': encSecKey}


# 通过参数获取搜索歌曲的列表
def get_music_list(params, encSecKey):
    url = "https://music.163.com/weapi/cloudsearch/get/web?csrf_token="

    payload = 'params=' + parse.quote(params) + '&encSecKey=' + parse.quote(encSecKey)
    headers = {
        'authority': 'music.163.com',
        'user-agent': UserAgent().random,
        'content-type': 'application/x-www-form-urlencoded',
        'accept': '*/*',
        'origin': 'https://music.163.com',
        'sec-fetch-site': 'same-origin',
        'sec-fetch-mode': 'cors',
        'sec-fetch-dest': 'empty',
        'referer': 'https://music.163.com/search/',
        'accept-language': 'zh-CN,zh;q=0.9',
    }
    response = requests.request("POST", url, headers=headers, data=payload)
    return response.text


# 通过歌曲的id获取播放链接
def get_reply(params, encSecKey):
    url = "https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token="
    payload = 'params=' + parse.quote(params) + '&encSecKey=' + parse.quote(encSecKey)
    headers = {
        'authority': 'music.163.com',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36',
        'content-type': 'application/x-www-form-urlencoded',
        'accept': '*/*',
        'origin': 'https://music.163.com',
        'sec-fetch-site': 'same-origin',
        'sec-fetch-mode': 'cors',
        'sec-fetch-dest': 'empty',
        'referer': 'https://music.163.com/',
        'accept-language': 'zh-CN,zh;q=0.9'
    }
    response = requests.request("POST", url, headers=headers, data=payload)
    return response.text

def res():
    url_list=[]
    name_list=[]
    song_name = input('请输入歌曲名称,按回车键搜索:')
    d = {"hlpretag": "<span class=\"s-fc7\">", "hlposttag": "</span>", "s": song_name, "type": "1", "offset": "0",
         "total": "true", "limit": "30", "csrf_token": ""}
    d = json.dumps(d)
    random_param = get_random()
    param = get_final_param(d, random_param)
    song_list = get_music_list(param['params'], param['encSecKey'])
    print('搜索结果如下:')
    if len(song_list) > 0:
        song_list = json.loads(song_list)['result']['songs']
        for i, item in enumerate(song_list):
            item = json.dumps(item)
            print(str(i+1) + ":" + json.loads(str(item))['name'])
            d = {"ids": "[" + str(json.loads(str(item))['id']) + "]", "level": "standard", "encodeType": "",
                 "csrf_token": ""}
            d = json.dumps(d)
            param = get_final_param(d, random_param)
            song_info = get_reply(param['params'], param['encSecKey'])
            if len(song_info) > 0:
                song_info = json.loads(song_info)
                song_url = json.dumps(song_info['data'][0]['url'], ensure_ascii=False) # 歌曲url
                print(song_url)
                url_list.append(song_url) # url放入列表
                name_list.append(json.loads(str(item))['name'])
            else:
                print("该首歌曲解析失败,可能是因为歌曲格式问题")
        """
            歌曲下载界面
        """
        while True:
            print('下载选择:1-20,ALL全部,Q返回查找,Z退出程序,显示为null的表示没有版权或vip才能下载')
            song_id = input('请输入下载编号:')
            if song_id=='ALL':
                for j in range(len(url_list)):
                    url = url_list[j].replace('"', '')
                    name = name_list[j] + url.split('/')[-1].split('.')[0]
                    try:
                        mp3 = requests.get(url=url, headers={'User-Agent': UserAgent().random}).content
                        with open(f'./{name}.mp3', 'wb') as f:
                            f.write(mp3)
                            print(name, "下载完成!")
                    except:
                        print(name,'这首歌无法下载!')
                        continue

                    else:
                        print('这首歌已下载!')
                break
            if song_id=='Q':
                res()
                break
            if song_id=='Z':
                print('退出下载!')
                break
            if int(song_id)>=1 and int(song_id)<=20:
                # print(str(url_list[song_id-1]),name_list[song_id-1])
                url=url_list[int(song_id) - 1].replace('"','')
                name=name_list[int(song_id)-1]+url.split('/')[-1].split('.')[0]
                try:
                    mp3 = requests.get(url=url,headers={'User-Agent':UserAgent().random}).content
                except:
                    print(name,'这首歌无法下载!')
                    continue
                with open(f'./{name}.mp3','wb') as f:
                    f.write(mp3)
                    print(name,"下载完成!")
            else:
                print('请根据提示输入!本次程序')
                res()
                break
    else:
        print("很抱歉,未能搜索到相关歌曲信息")


if __name__ == '__main__':
    res()
代码参考:https://blog.csdn.net/zgbzbl/article/details/107773755?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_utm_term~default-0.no_search_link&spm=1001.2101.3001.4242
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值