python 根据列表批量下载网易云音乐的免费音乐


Posted in Python onDecember 03, 2020

运行效果

python 根据列表批量下载网易云音乐的免费音乐

代码

# -*- coding:utf-8 -*-
import requests, hashlib, sys, click, re, base64, binascii, json, os
from Crypto.Cipher import AES
from http import cookiejar

"""
Website:http://cuijiahua.com
Author:Jack Cui
Refer:https://github.com/darknessomi/musicbox
"""

class Encrypyed():
	"""
	解密算法
	"""
	def __init__(self):
		self.modulus = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'
		self.nonce = '0CoJUm6Qyw8W8jud'
		self.pub_key = '010001'

	# 登录加密算法, 基于https://github.com/stkevintan/nw_musicbox脚本实现
	def encrypted_request(self, text):
		text = json.dumps(text)
		sec_key = self.create_secret_key(16)
		enc_text = self.aes_encrypt(self.aes_encrypt(text, self.nonce), sec_key.decode('utf-8'))
		enc_sec_key = self.rsa_encrpt(sec_key, self.pub_key, self.modulus)
		data = {'params': enc_text, 'encSecKey': enc_sec_key}
		return data

	def aes_encrypt(self, text, secKey):
		pad = 16 - len(text) % 16
		text = text + chr(pad) * pad
		encryptor = AES.new(secKey.encode('utf-8'), AES.MODE_CBC, b'0102030405060708')
		ciphertext = encryptor.encrypt(text.encode('utf-8'))
		ciphertext = base64.b64encode(ciphertext).decode('utf-8')
		return ciphertext

	def rsa_encrpt(self, text, pubKey, modulus):
		text = text[::-1]
		rs = pow(int(binascii.hexlify(text), 16), int(pubKey, 16), int(modulus, 16))
		return format(rs, 'x').zfill(256)

	def create_secret_key(self, size):
		return binascii.hexlify(os.urandom(size))[:16]


class Song():
	"""
	歌曲对象,用于存储歌曲的信息
	"""
	def __init__(self, song_id, song_name, song_num, song_url=None):
		self.song_id = song_id
		self.song_name = song_name
		self.song_num = song_num
		self.song_url = '' if song_url is None else song_url

class Crawler():
	"""
	网易云爬取API
	"""
	def __init__(self, timeout=60, cookie_path='.'):
		self.headers = {
			'Accept': '*/*',
			'Accept-Encoding': 'gzip,deflate,sdch',
			'Accept-Language': 'zh-CN,zh;q=0.8,gl;q=0.6,zh-TW;q=0.4',
			'Connection': 'keep-alive',
			'Content-Type': 'application/x-www-form-urlencoded',
			'Host': 'music.163.com',
			'Referer': 'http://music.163.com/search/',
			'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'
		}
		self.session = requests.Session()
		self.session.headers.update(self.headers)
		self.session.cookies = cookiejar.LWPCookieJar(cookie_path)
		self.download_session = requests.Session()
		self.timeout = timeout
		self.ep = Encrypyed()

	def post_request(self, url, params):
		"""
		Post请求
		:return: 字典
		"""

		data = self.ep.encrypted_request(params)
		resp = self.session.post(url, data=data, timeout=self.timeout)
		result = resp.json()
		if result['code'] != 200:
			click.echo('post_request error')
		else:
		  return result

	def search(self, search_content, search_type, limit=9):
		"""
		搜索API
		:params search_content: 搜索内容
		:params search_type: 搜索类型
		:params limit: 返回结果数量
		:return: 字典.
		"""

		url = 'http://music.163.com/weapi/cloudsearch/get/web?csrf_token='
		params = {'s': search_content, 'type': search_type, 'offset': 0, 'sub': 'false', 'limit': limit}
		result = self.post_request(url, params)
		return result

	def search_song(self, song_name, song_num, quiet=True, limit=9):
		"""
		根据音乐名搜索
		:params song_name: 音乐名
		:params song_num: 下载的歌曲数
		:params quiet: 自动选择匹配最优结果
		:params limit: 返回结果数量
		:return: Song独享
		"""

		result = self.search(song_name, search_type=1, limit=limit)

		if result['result']['songCount'] <= 0:
			click.echo('Song {} not existed.'.format(song_name))
		else:
			songs = result['result']['songs']
			if quiet:
				song_id, song_name = songs[0]['id'], songs[0]['name']
				song = Song(song_id=song_id, song_name=song_name, song_num=song_num)
				return song

	def get_song_url(self, song_id, bit_rate=320000):
		"""
		获得歌曲的下载地址
		:params song_id: 音乐ID<int>.
		:params bit_rate: {'MD 128k': 128000, 'HD 320k': 320000}
		:return: 歌曲下载地址
		"""

		url = 'http://music.163.com/weapi/song/enhance/player/url?csrf_token='
		csrf = ''
		params = {'ids': [song_id], 'br': bit_rate, 'csrf_token': csrf}
		result = self.post_request(url, params)
		# 歌曲下载地址
		song_url = result['data'][0]['url']

		# 歌曲不存在
		if song_url is None:
			click.echo('Song {} is not available due to copyright issue.'.format(song_id))
		else:
			return song_url

	def get_song_by_url(self, song_url, song_name, song_num, folder):
		"""
		下载歌曲到本地
		:params song_url: 歌曲下载地址
		:params song_name: 歌曲名字
		:params song_num: 下载的歌曲数
		:params folder: 保存路径
		"""
		if not os.path.exists(folder):
			os.makedirs(folder)
		fpath = os.path.join(folder, str(song_num) + '_' + song_name + '.mp3')
		if sys.platform == 'win32' or sys.platform == 'cygwin':
			valid_name = re.sub(r'[<>:"/\\|?*]', '', song_name)
			if valid_name != song_name:
				click.echo('{} will be saved as: {}.mp3'.format(song_name, valid_name))
				fpath = os.path.join(folder, str(song_num) + '_' + valid_name + '.mp3')
		
		if not os.path.exists(fpath):
			resp = self.download_session.get(song_url, timeout=self.timeout, stream=True)
			length = int(resp.headers.get('content-length'))
			label = 'Downloading {} {}kb'.format(song_name, int(length/1024))

			with click.progressbar(length=length, label=label) as progressbar:
				with open(fpath, 'wb') as song_file:
					for chunk in resp.iter_content(chunk_size=1024):
						if chunk:
							song_file.write(chunk)
							progressbar.update(1024)


class Netease():
	"""
	网易云音乐下载
	"""
	def __init__(self, timeout, folder, quiet, cookie_path):
		self.crawler = Crawler(timeout, cookie_path)
		self.folder = '.' if folder is None else folder
		self.quiet = quiet

	def download_song_by_search(self, song_name, song_num):
		"""
		根据歌曲名进行搜索
		:params song_name: 歌曲名字
		:params song_num: 下载的歌曲数
		"""

		try:
			song = self.crawler.search_song(song_name, song_num, self.quiet)
		except:
			click.echo('download_song_by_serach error')
		# 如果找到了音乐, 则下载
		if song != None:
			self.download_song_by_id(song.song_id, song.song_name, song.song_num, self.folder)

	def download_song_by_id(self, song_id, song_name, song_num, folder='.'):
		"""
		通过歌曲的ID下载
		:params song_id: 歌曲ID
		:params song_name: 歌曲名
		:params song_num: 下载的歌曲数
		:params folder: 保存地址
		"""
		try:
			url = self.crawler.get_song_url(song_id)
			# 去掉非法字符
			song_name = song_name.replace('/', '')
			song_name = song_name.replace('.', '')
			self.crawler.get_song_by_url(url, song_name, song_num, folder)

		except:
			click.echo('download_song_by_id error')


if __name__ == '__main__':
	timeout = 60
	output = 'Musics'
	quiet = True
	cookie_path = 'Cookie'
	netease = Netease(timeout, output, quiet, cookie_path)
	music_list_name = 'music_list.txt'
	# 如果music列表存在, 那么开始下载
	if os.path.exists(music_list_name):
		with open(music_list_name, 'r') as f:
			music_list = list(map(lambda x: x.strip(), f.readlines()))
		for song_num, song_name in enumerate(music_list):
			netease.download_song_by_search(song_name,song_num + 1)
	else:
		click.echo('music_list.txt not exist.')

以上就是python 根据列表批量下载网易云音乐的免费音乐的详细内容,更多关于python 网易云音乐下载的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python中的装饰器详解
Apr 13 Python
如何在Python函数执行前后增加额外的行为
Oct 20 Python
安装Python和pygame及相应的环境变量配置(图文教程)
Jun 04 Python
pandas 将list切分后存入DataFrame中的实例
Jul 03 Python
Python3 chardet模块查看编码格式的例子
Aug 14 Python
关于pytorch多GPU训练实例与性能对比分析
Aug 19 Python
Python中list循环遍历删除数据的正确方法
Sep 02 Python
python使用pip安装SciPy、SymPy、matplotlib教程
Nov 20 Python
Python底层封装实现方法详解
Jan 22 Python
Python发送手机动态验证码代码实例
Feb 28 Python
keras读取h5文件load_weights、load代码操作
Jun 12 Python
keras中的History对象用法
Jun 19 Python
python中字符串的编码与解码详析
Dec 03 #Python
python 爬取百度文库并下载(免费文章限定)
Dec 04 #Python
filter使用python3代码进行迭代元素的实例详解
Dec 03 #Python
python3代码输出嵌套式对象实例详解
Dec 03 #Python
python3代码中实现加法重载的实例
Dec 03 #Python
python判断all函数输出结果是否为true的方法
Dec 03 #Python
django中cookiecutter的使用教程
Dec 03 #Python
You might like
Flash空降上海 化身大魔王接受挑战
2020/03/02 星际争霸
PHP入门速成教程
2007/03/19 PHP
php下使用SimpleXML 处理XML 文件
2010/02/27 PHP
php HandlerSocket的使用
2011/05/02 PHP
PHP 无限分类三种方式 非函数的递归调用!
2011/08/26 PHP
php中require和require_once的区别说明
2014/02/27 PHP
php事务处理实例详解
2014/07/11 PHP
PHP实现文件上传功能实例代码
2017/05/18 PHP
php实现保存周期为1天的购物车类
2017/07/07 PHP
总结一些js自定义的函数
2006/08/05 Javascript
使用jquery给input和textarea设定ie中的focus
2008/05/29 Javascript
js函数使用技巧之 setTimeout(function(){},0)
2009/02/09 Javascript
Mootools 1.2教程 Tooltips
2009/09/15 Javascript
Javascript动态引用CSS文件的2种方法介绍
2014/06/06 Javascript
jquery实现仿JqueryUi可拖动的DIV实例
2015/07/31 Javascript
jQuery树插件zTree使用方法详解
2017/05/02 jQuery
详解vue-meta如何让你更优雅的管理头部标签
2018/01/18 Javascript
修改Nodejs内置的npm默认配置路径方法
2018/05/13 NodeJs
微信小程序实现图片滚动效果示例
2018/12/05 Javascript
小试SVG之新手小白入门教程
2019/01/08 Javascript
深入浅析vue-cli@3.0 使用及配置说明
2019/05/08 Javascript
使用Vue-cli3.0创建的项目 如何发布npm包
2019/10/10 Javascript
JavaScript Event Loop相关原理解析
2020/06/10 Javascript
[01:02:20]Mineski vs TNC 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/16 DOTA
Python写入CSV文件的方法
2015/07/08 Python
python递归打印某个目录的内容(实例讲解)
2017/08/30 Python
python处理Excel xlrd的简单使用
2017/09/12 Python
Python编程二分法实现冒泡算法+快速排序代码示例
2018/01/15 Python
使用JS+CSS3技术:让你的名字动起来
2013/04/27 HTML / CSS
Kathmandu澳洲户外商店:新西兰户外运动品牌
2017/11/12 全球购物
苹果Mac升级:MacSales.com
2017/11/20 全球购物
static函数与普通函数有什么区别
2015/12/25 面试题
护理中职生求职信范文
2014/02/24 职场文书
外语系大学生自荐信范文
2014/03/01 职场文书
2015年小学实验室工作总结
2015/07/28 职场文书
Flink 侧流输出源码示例解析
2022/09/23 Servers