之前写过一篇网易云的文章,但是一直不过审,这几天搞QQ音乐的爬虫,JS逆向不是很顺利,有点忘了怎么搞了,所以今天打断点重搞一把网易云音乐,毕竟是之前搞过的
找加密函数
最下面有个url就是歌曲mp3文件的url,也就是目标url
接下来看这个请求url携带的俩个参数(post类型)
记住他们俩的名字,开始整活
康康发起程序里面是什么,点第三个进去,这个界面
点这个
然后是这个界面
这是我已经打了断点的结果,现在解释为什么要在这打断点
打断点
还记得第二个参数吧,ctrl+f搜索
第一个就是加密函数本身,不信看后面俩个匹配项,
可以看到 params , encSecKey 都是根据 bwv4z 来的,
那bwv4z 是什么函数?方法一:
上面那个core d84链接点进去
方法二:
直接搜索window.asrsea
而bwv4z 是根据 window.asrsea() 函数来的,window.asrsea就是function d(d, e, f, g), 所以在这个 函数打断点
ctrl+r刷新等待一下
看这个右栏的作用域
这就是函数d需要的几个参数,多刷新几次,发现后面三个参数固定不变,第一个参数我给打印出来"{“csrf_token”:“ccea8e32b28180ce17986067edb5efbf”}"这个是你的账号,判断是否登录
为什么参数和函数都是啊a,b,c,d,就是混淆,也算是反爬虫
按照上面的办法看看函数a,b,c是什么用处
函数a
function a(a) {
var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";
for (d = 0; a > d; d += 1)
e = Math.random() * b.length,
e = Math.floor(e),
c += b.charAt(e);
return c
}
看不懂,用python解释一下
import random
def make_random():
str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
random_str = ''
for i in range(16) :
index = random.randint(0, len(str) - 1)
random_str += str[index]
return random_str
就是生成一个16位随机字符串
函数b
function b(a, b) {
var c = CryptoJS.enc.Utf8.parse(b)
, d = CryptoJS.enc.Utf8.parse("0102030405060708")
, e = CryptoJS.enc.Utf8.parse(a)
, f = CryptoJS.AES.encrypt(e, c, {
iv: d,
mode: CryptoJS.mode.CBC
});
return f.toString()
}
已经把函数的名字写到明面上了,AES加密CBC模式
我上一篇文章讲过AES和RSA,自己去看,给个关注就更好了
函数c
https://editor.csdn.net/md/?articleId=113795115这是我的文章,讲的RSA加密,我觉得挺详细的
RSA加密
高能预警
上爬虫代码
import json,base64,random,requests,re,os
from Crypto.Util.Padding import pad
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
from binascii import hexlify
def add_to_16(text):
# 补全成16的倍数
if len(text.encode('utf-8')) % 16:
add = 16 - (len(text.encode('utf-8')) % 16)
else:
add = 0
text = text + ('\0' * add)
return text.encode('utf-8')
def make_random():
str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
random_str = ''
for i in range(16) :
index = random.randint(0, len(str) - 1)
random_str += str[index]
return random_str
def AESEncrypt(clear_text, key):
"""
AES加密, 对应函数b
:param clear_text: 需要加密的数据
:return:
"""
# 数据填充
clear_text = pad(data_to_pad=clear_text.encode(), block_size=AES.block_size)
key = key.encode()
iv = '0102030405060708'
iv = iv.encode()
aes = AES.new(key=key, mode=AES.MODE_CBC, iv = iv)
cipher_text = aes.encrypt(plaintext=clear_text)
# 字节串转为字符串
cipher_texts = base64.b64encode(cipher_text).decode()
return cipher_texts
def make_params_encSecKey(text):
# song_name = input('要下载歌曲的名字:')
text = json.dumps(text)
key = '0CoJUm6Qyw8W8jud'
# key = key.encode('utf-8')
frist_aes =AESEncrypt(text,key)
random_str = make_random()
encSecKey = make_encSecKey(random_str)
# print(frist_aes)
fan_key = frist_aes.encode()
params = AESEncrypt(frist_aes,random_str)
# print(params)
data = {
'params': params,
'encSecKey': encSecKey
}
return data
# fanl_text = str(frist_aes,encoding='utf-8')
# parmas = aes_encrypt(fanl_text,random_str)
def make_encSecKey(text):
text = text[::-1]
modulus = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'
pub_key = '010001'
rs = pow(int(hexlify(text.encode('utf-8')), 16), int(pub_key, 16), int(modulus, 16))
return format(rs, 'x').zfill(256)
def print_id_list(data):
# data = make_params_encSecKey()
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
id_url = 'https://music.163.com/weapi/cloudsearch/get/web?csrf_token='
response = requests.post(id_url,data,headers).text
# print(response.text)
# names = re.findall(r'"name":"(.*?)"',response)
# ids = re.findall(r'","id":(.*?),"pst"',response)
# i = 0
# for id in ids :
# # a = int(id)
# # if a>10000 and a<100000 :
# print(i,id)
# i = i+1
# print(i)
ids_list = json.loads(response)['result']['songs']
count = 0
info_list = []
print('只显示前20首歌,如果不够用换个带歌手的关键词搜索')
print('{:-^80}'.format('-'))
print('{0:{5}<5}{1:{5}<20}{2:{5}<10}{3:{5}<10}{4:{5}<20}'.format('序号', '歌名', '歌手', '时长(s)', '专辑', chr(12288)))
print('{:-^84}'.format('-'))
for id_info in ids_list:
song_name = id_info['name']
id = id_info['id']
time = id_info['dt'] // 1000
album_name = id_info['al']['name']
picture_url = id_info['al']['picUrl']
singer = id_info['ar'][0]['name']
info_list.append([id, song_name, singer])
print('{0:{5}<5}{1:{5}<20}{2:{5}<10}{3:{5}<10}{4:{5}<20}'.format(count, song_name, singer, time, album_name, chr(12288)))
count += 1
if count == 20:
# 为了测试方便, 这里只显示了9条数据
break
print('{:-^80}'.format('-'))
return info_list
if __name__ == '__main__':
song_name = input("请输入要下载的歌曲,需要买专辑和无版权的不可下载")
text = {"hlpretag": "<span class=s-fc7>", "hlposttag": "</span>", "s": song_name, "type": "1", "offset": "0",
"total": "true", "limit": "50", "csrf_token": ""}
data = make_params_encSecKey(text)
# print(text)
ids_list = print_id_list(data)
while True:
input_index = eval(input("请输入要下载歌曲的序号(按666退出): "))
if input_index == 666:
break
download_info = ids_list[input_index]
song_d = {
"ids": str([download_info[0]]),
"level": " ",
"encodeType": "aac",
"csrf_token": ""
}
# print(song_d)
# 把song_d用AES和RSA加密以后变成params和en写进请求
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
data = make_params_encSecKey(song_d)
# print(data)
song_url = 'https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token='
song_response = requests.post(song_url,data,headers).text
# print(song_response)
inti_download_url = re.findall(r'"url":"(.*?)","', song_response,re.S)
# print(inti_download_url[0])
# download_url = re.findall(r'[(.*?)]', inti_download_url, re.S)
# print(download_url)
# download_url = 1+inti_download_url
# print(download_url[0])
download_location = r'D:'
# os.mkdir('d:\网易云音乐下载')
download_song = requests.get(inti_download_url[0],headers)
name=str(song_name)+'.mp3'
with open(name, 'wb') as f:
f.write(download_song.content)
print("下载成功")
上效果图