网易云音乐python爬虫(Js破解)

网易云音乐下载python爬虫(Js破解)

最近做了一个网易云音乐下载的python爬虫,功能就是输入歌曲的名字,程序自动下载网易音乐搜索界面的第一首歌(一般都是原唱排第一位)。本文很适合小白学习,写的很详细,不信的话你试试看!!

需要用到的工具

1.python3.7
2.chrome浏览器
3.sublime编辑器
话不多说,下面开始讲解流程。

主要流程

1.在网易云音乐搜索框中输入“成都”,F12打开开发者模式,搜索框回车,在Network中发现出现了很多响应数据,点进每个响应,切换到右边一栏的Preview。
歌曲列表在web?csrf_token=中我们发现响应result是一个json格式的数据,在songs字段中出现了歌曲列表。
id字段
在这里插入图片描述
当我们把鼠标放到页面第一首歌曲的上面是,屏幕左下方的链接显示的id刚好就是json数据中id,于是我们找到了歌曲的id,或许有用,接着往下看。
2.
在这里插入图片描述随机点击一首歌进行播放,注意不要点击超链接,那样会跳转页面,点击那个小的播放按钮就可以了。点击播放按钮后左侧导航栏里面会多了几个响应,其中就有一个MP3文件。在这里插入图片描述可以看到浏览器发送了一个GET请求,服务器响应一个mp3文件,如果我们在python程序里面也向Request URL发送一个GET请求,那样不就能下载MP3文件了吗。思路逐渐清晰,于是我们接下来的任务就是寻找到这个URL是从哪里得到的,再重新查看左侧的导航栏,发现在播放歌曲的时候多了一个url?csrf_token=的响应,点进去看Headers,发现是一个POST请求,参数有两个,params和encSecKey,点击Preview,可以看到也是一个json数据,有没有发现我们的响应里面有个url字段,他的地址和我们MP3响应的请求地址是一样的。在这里插入图片描述在这里插入图片描述
在这里插入图片描述很好,大致思路已经有了,就是首先向服务器的url?csrf_token=发送一个POST请求,得到MP3文件的请求地址,再向这个地址发送GET请求就能得到mp3文件。那么问题来了,url?csrf_token=的POST请求的参数怎么办?接着往下看吧!
3.
关闭右侧的导航栏,点击红色箭头所指向的文件,打开后是一个JS文件。在这里插入图片描述在这里插入图片描述点击格式化,这样看的舒服一点。按住Ctrl+F,打开查找搜索框,输入encSecKey。在这里插入图片描述在bLi4m这个变量中含有我们需要的参数。这个bLi4m变量接收的是window.asrsea这个函数返回的数据,将鼠标放到这个函数上面出现一个对话框,是一个d函数,点进去,跳转到了function d()。在这里插入图片描述在function d中多设置几个断点,function d接收d,e,f,g四个参数,我们想要看看着四个参数到底是什么,下面演示断点调试。
4.
我们设置好断点后,刷新页面,js会执行到第一个断点处。
在这里插入图片描述可以看到粉色的是已经执行过的程序变量的值,再次点击红色箭头所指的按钮,程序运行到function d处暂停。在这里插入图片描述在这里插入图片描述在右边的导航栏的Scope中看到d: “{“ids”:”[456185373]",“br”:128000,“csrf_token”:""}"
e: “010001”
f:“00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7”
g: “0CoJUm6Qyw8W8jud”。这就是function d的四个参数,解析function d。在这里插入图片描述函数d首相执行函数a,在执行两次b函数,最后执行c函数。在这里插入图片描述a函数就是在一串字符串中随机挑选16个字符组成随机字符串。在这里插入图片描述
b函数刚开始我也没有看懂什么意思,后来学习了一篇文章Python爬虫之网易云音乐下载,大家也可以去看看学习一下。函数b实现的是一个AES加密的过程,至于AES加密大家可以百度看看,有很多文章介绍,python实现这个加密算法也很简单,直接调用函数就可以了。函数b的作用就是将传进去的a,b参数进行加密,其中a是密文,b是偏移量,密钥在函数中给定,是0102030405060708,b函数就说到这里,下面看c函数。在这里插入图片描述c函数实现的是RSA加密,参数a是16位的随机字符串,参数b,c分别是d函数中的e,f常量。好了现在a,b,c函数都已经解析过了,回头来看看d函数,d函数中执行了两次的AES加密,第一次加密的结果作为第二次加密的密文连同16位的随机字符串,再次加密,而RSA加密只执行一次,需要注意的是在整个加密的过程中,随机字符串使用的始终是同一个字符串。在这里插入图片描述到这里为止,整个加密过程基本解析完毕,下面开始上代码。
5.
安装 PyCryptodome库,直接pip install PyCryptodome就行。
生成16位随机字符串,也就是一个for循环的事。

def get_random_str():
	str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
	random_str = '';
	for i in range(16):
		index = random.randint(0,len(str)-1);
		random_str += str[index];
	return random_str;

AES加密

def aes_encrypt(text,key):#text是要加密的密文,key是密钥
	iv = b'0102030405060708';
	pad = 16 - len(text) % 16;
	text = text + chr(2) * pad;#这个是将不足16倍数的密文补全到16的倍数,没有这个会报错
	encryptor = AES.new(key.encode(),AES.MODE_CBC,iv);
	encryptor_str = encryptor.encrypt(text.encode());#这一定要UTF-8编码
	result_str = base64.b64encode(encryptor_str).decode();
	return result_str;

AES要加密的密文是 “{“ids”:”[song_id]",“br”:128000,“csrf_token”:""}",只要将其中的song_id替换成歌曲的id就行了,就是上面说到的POST请求得到的id。
RSA加密

def rsa_encrypt(text):#text是16位的随机字符串
	pub_key = '010001';#js中的e
	# js中的f
	modulus = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'
	text = text[::-1];
	result = pow(int(hexlify(text.encode()),16),int(pub_key,16),int(modulus,16));
	return format(result,'x').zfill(131);

RSA加密的密文是16位的随机字符串,要和AES加密保持一致。
6.
介绍完加密过程,下面介绍获取歌曲id,毕竟我们要实现的是下载任意的歌曲。输入歌曲名字就能下载,要实现这个功能就必须得到id,然后通过上文加密方法,获得params和encSecKey参数发送POST请求回去下载的url。在这里插入图片描述这里我们发现了获取id的url,查看其request请求。在这里插入图片描述在这里插入图片描述同样的这也是一个post请求,参数还是params和encSecKey,和上面加密一样,查看其js文件,进行断点调试,有了上面的经验,这次我们重点查看d函数就行了。在这里插入图片描述可以看到这次d函数传入的参数基本没有变,只有d参数稍有变化,变成了"{“hlpretag”:"<span class=“s-fc7”>",“hlposttag”:"","#/download":"",“s”:“成都”,“type”:“1”,“offset”:“0”,“total”:“true”,“limit”:“30”,“csrf_token”:""}",其中s字段就是我们要搜索的歌曲名字,还是按照前面的加密过程一样得到post参数,到这里整个过程基本结束,下面贴上完整的代码。
7.
程序流程就是,首先输入想要下载歌曲的名字,然后拼接密文字符串进行加密,获得歌曲的id,再通过id获取下载的链接,其中由于获取的歌曲id有很多个,我只选择下载第一个(一般都是原唱),程序写的很简单,但基本功能已经实现,大家可以学习一下。

import random
import requests
from Crypto.Cipher import AES
from binascii import hexlify
import json
import base64
from pprint import pprint
import os

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',
			'Cookie':'_iuqxldmzr_=32; _ntes_nnid=3781266ef61a5aa2d7ede27aa0183bc1,1551083564434; _ntes_nuid=3781266ef61a5aa2d7ede27aa0183bc1; WM_TID=OZGc1XNosq1FFVUURUIpkhlLoMCtrNMy; WM_NI=8rKLP6ufZLsNyeHmP9SDIvgYp6Yeuuu9ZGfzbCvvrI%2B%2FXUYhDsvVVFRPPcN1ekPJXIbE%2FYcXpJhEf9dT8jQQUfTaONE8iXIYAb%2F6FvZ0Xr4hoDjDHTgTPQpejvbJ0%2FIHU2Q%3D; WM_NIKE=9ca17ae2e6ffcda170e2e6ee92ef80fbaeb9d8b67b94a88ab2c85e829b9aafee7df4eda58df544a68f00d7ae2af0fea7c3b92afcae85add33eb7ba96adf246bbbb888ed333919c8797e653b4ea9786f87fb7e796a8e572a29dba97f143e9f198b6dc6488adbab7d54e9290a084cd3ba7b5a0abdb43a29be1bae254b496a8a6e533a88cf88bd45b97ba9c82ce4687e8a7b9cc5383bee1d7c57e9af09893b764ad9ca6a5cb60a58ca0b2f36faaaaaeabb3258b989bd3d437e2a3; JSESSIONID-WYYY=%2B0ojNXAeyKT7wKzj1AnD3RXYergSXK5S70VlZwNdlKqvuFDjOfb1Ao2PGtbBUf38RohOpdmBfcMpY3eM2jp5WiRsaJ22nosm%2F1AwqaJgomKkGAY5VfXyM%2BcVUrlgTEZFHaMNUcePUXY05Ks23XgW4yr1gPmb%2FJbtbks9nbC0OUlX82cn%3A1551237928176'
		};

def get_random_str():
	str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
	random_str = '';
	for i in range(16):
		index = random.randint(0,len(str)-1);
		random_str += str[index];
	return random_str;

def aes_encrypt(text,key):#text是要加密的密文,key是密钥
	iv = b'0102030405060708';
	pad = 16 - len(text) % 16;
	text = text + chr(2) * pad;
	encryptor = AES.new(key.encode(),AES.MODE_CBC,iv);
	encryptor_str = encryptor.encrypt(text.encode());
	result_str = base64.b64encode(encryptor_str).decode();
	return result_str;

def rsa_encrypt(text):#text是16位的随机字符串
	pub_key = '010001';#js中的e
	# js中的f
	modulus = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'
	text = text[::-1];
	result = pow(int(hexlify(text.encode()),16),int(pub_key,16),int(modulus,16));
	return format(result,'x').zfill(131);

#b函数,两次AES加密
def get_aes(text,random_str):
	first_aes = aes_encrypt(text,key='0CoJUm6Qyw8W8jud');#key是固定的,相当于g
	second_aes = aes_encrypt(first_aes,random_str);
	return second_aes;

#获取加密的参数
def get_post_data(text,random_str):
	params = get_aes(text,random_str);
	encSecKey = rsa_encrypt(random_str);
	return {'params':params,'encSecKey':encSecKey};


def get_song_list(song_name,random_str):
	#要加密的字符串
	text = {"hlpretag":"<span class=s-fc7>","hlposttag":"</span>","s":song_name,"type":"1","offset":"0","total":"true","limit":"50","csrf_token":""};
	text = json.dumps(text);
	data = get_post_data(text,random_str);
	url = 'https://music.163.com/weapi/cloudsearch/get/web?csrf_token=';
	return post_requests(url,data);

def post_requests(url,data):
	session = requests.Session();
	session.headers.update(headers);
	re = session.post(url,data=data);
	return re.json();


def get_song_url(song_id,random_str):
	#'MD 128k': 128000, 'HD 320k': 320000
	text = {'ids': [song_id], 'br': 128000, 'csrf_token': ''};
	text = json.dumps(text);
	data = get_post_data(text,random_str);
	url = 'https://music.163.com/weapi/song/enhance/player/url?csrf_token=';
	return post_requests(url,data);

if __name__ == '__main__':
	random_str = get_random_str();
	song_name = input('输入歌曲名:')
	song_list = get_song_list(song_name,random_str);
	id = song_list['result']['songs'][0]['id'];
	song_url = get_song_url(id,random_str)['data'][0]['url'];
	if not os.path.exists(song_name):
		os.mkdir(song_name);#新建文件夹
	with open(song_name+'/'+song_name+'.mp3','wb') as f:
		try:
			response = requests.get(song_url, timeout=10);
		except requests.exceptions.ConnectTimeout:#超时重新请求
			response = requests.get(song_url, timeout=10);
		f.write(response.content);

我在写程序的时候参考了github上面的一个项目,大家有兴趣也可以去学习一下,地址在这里

写在最后

这次破解网易云音乐学到了很多小的技能,像js的断点调试,AES和RSA加密,前前后后花了不少的心思,看了很多文档,在这里也向乐于分享自己技术的前辈们致敬!

  • 49
    点赞
  • 181
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
### 回答1: 你可以使用 Python 的 requests 库和 Beautiful Soup 库来爬取音乐推荐网站的信息,例如豆瓣音乐、网易云音乐等。首先,你需要了解如何使用 requests 库发送 HTTP 请求获取网页源代码,然后使用 Beautiful Soup 库解析 HTML 文档提取需要的信息。在爬取音乐推荐时,你可能需要考虑如何处理动态加载的数据,例如使用 Selenium 等库模拟浏览器行为。另外,你需要了解相关网站的爬虫规则和法律法规,遵守网站的访问频率限制和反爬虫策略。 ### 回答2: Python音乐推荐爬虫是一种利用Python编程语言来实现的网络爬虫工具,用于自动化收集、分析和推荐音乐。 首先,这个爬虫需要使用Python的网络请求库(例如requests)向音乐服务端发送HTTP请求,并获取音乐数据。可以通过解析服务端的响应,获取音乐的相关信息,如音乐名称、歌手、专辑、时长等。 接下来,可以使用Python的数据处理和分析库,如pandas、NumPy等,对获取的音乐数据进行处理和分析。可以根据用户的历史听歌记录、最近听歌趋势等数据,来推荐用户感兴趣的音乐。 在音乐推荐方面,可以使用Python的机器学习和推荐系统算法库,如scikit-learn、TensorFlow等。可以训练机器学习模型,根据用户的个人特征和历史听歌数据,为用户推荐最符合其喜好的音乐。 此外,还可以使用Python的可视化库,如matplotlib、Seaborn等,将分析结果和推荐音乐以图表形式展示,方便用户查看和理解。 最后,可以使用Python的web框架,如Django、Flask等,将上述功能整合成一个Web应用程序,提供用户界面,让用户可以方便地搜索、播放、收藏音乐,并根据推荐系统的结果发现新的音乐。 总之,Python音乐推荐爬虫利用Python的强大功能和丰富的库,能够实现自动化收集、分析和推荐音乐的功能,并为用户提供个性化的音乐体验。 ### 回答3: 音乐推荐爬虫是一种利用爬虫技术来获取音乐推荐信息的工具。Python作为一种强大的编程语言,拥有丰富的库和模块,适合用来编写爬虫程序。 首先,我们需要选择合适的音乐网站作为爬取目标。例如,可以选择一些流行的音乐平台,如网易云音乐、QQ音乐等。这些平台都提供了丰富的音乐资源和推荐系统,可以作为我们获取音乐信息的源。 其次,我们需要使用Python中的库来实现爬虫功能。常用的库有requests、BeautifulSoup和selenium等。利用requests库发送HTTP请求,可以模拟用户浏览器的行为来获取网页内容;BeautifulSoup库可以用来解析网页内容,提取出我们需要的音乐信息;selenium库则可以用来模拟用户操作网页,例如点击按钮、滚动页面等。 接着,我们需要分析音乐平台的网页结构,确定需要爬取的信息。例如,我们可以获取音乐的标题、歌手、专辑、时长、播放次数等信息。通过解析网页内容,我们可以将这些信息提取出来,并保存到本地文件或数据库中。 最后,我们可以根据用户的喜好和推荐算法来给用户推荐适合的音乐。例如,可以根据用户的收听历史、喜欢的歌手等信息,利用机器学习算法进行音乐推荐。Python中的机器学习库,如scikit-learn和tensorflow等,可以帮助我们构建推荐算法模型。 总之,利用Python编写音乐推荐爬虫可以帮助我们获取音乐信息,并利用推荐算法为用户提供个性化的音乐推荐服务。
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值