潍坊做电商的网站,北京市违法建设投诉网站,简单网页设计主题,做公众号编辑用什么网站python爬虫获取网易云音乐评论歌词以及歌曲地址 一.寻找数据接口二.对负载分析三.寻找参数加密过程1.首先找到评论的请求包并找到发起程序2.寻找js加密的代码 四.扣取js的加密源码1.加密函数参数分析①.JSON.stringify(i0x)②bse6Y([流泪, 强])③bse6Y… python爬虫获取网易云音乐评论歌词以及歌曲地址 一.寻找数据接口二.对负载分析三.寻找参数加密过程1.首先找到评论的请求包并找到发起程序2.寻找js加密的代码 四.扣取js的加密源码1.加密函数参数分析①.JSON.stringify(i0x)②bse6Y([流泪, 强])③bse6Y(Qu1x.md)④.bse6Y([爱心, 女孩, 惊恐, 大笑]) 1.加密函数分析 五.在本地环境使用此函数1.直接将js代码复制并用js环境运行2.将js代码翻译为python代码 六.python代码 一.寻找数据接口
评论 url:https://music.163.com/weapi/comment/resource/comments/get 歌词 url:https://music.163.com/weapi/song/lyric 歌曲地址 url:https://music.163.com/weapi/song/enhance/player/url/v1
二.对负载分析
从三个接口的负载我们可以得出
data{
params:加密数据
encSecKey:加密数据
}所以我们只需要找出这个两个参数的加密过程就能模拟请求并得到我们想要的数据
三.寻找参数加密过程
因为这三个接口的加密是一样的这里我们用评论的接口来讲解
1.首先找到评论的请求包并找到发起程序 f12打开调试并且点击网络然后找到对应的包https://music.163.com/weapi/comment/resource/comments/get 点击发起程序
2.寻找js加密的代码
我们先点击发起程序的第一个进入到js文件中找到请求发出的地方也就是 send()函数 先加个断点然后刷新页面(下图) 刷新后我们就可以看到调用栈然后从第一个往下点一直找到send()(上图) 找到send()后我们取消掉前面的断点并给send打上断点然后再次刷新网页上图
这个url代表的是此次请求发送的url我们评论的url为https://music.163.com/weapi/comment/resource/comments/get所以我们点击上面的小三角放过此次请求直至抓取到我们所需的请求上图 我们现在就抓取到了评论请求的data数据等信息我们可以看到此时的信息还是加密的所以我们要继续向前找寻找到它未加密的地方(上图) data的加密数据在t0x这个调用栈前面是没有的所以我们就能确定数据是在这个调用栈中被加密然后我们ctrl F 直接搜索params就定位到了加密的函数
四.扣取js的加密源码
var bVi6c window.asrsea(JSON.stringify(i0x), bse6Y([流泪, 强]), bse6Y(Qu1x.md), bse6Y([爱心, 女孩, 惊恐, 大笑]));e0x.data j0x.cr1x({params: bVi6c.encText,encSecKey: bVi6c.encSecKey})根据上一步我们找到的源码我们可以看出 我们所需的两个加密数据 paramsencSecKey都是由 bVi6c产生的 bVi6c是由 这个函数生成的所以只需要取出这个函数的加密过程就能模拟出我们的加密数据
window.asrsea(JSON.stringify(i0x), bse6Y([流泪, 强]), bse6Y(Qu1x.md), bse6Y([爱心, 女孩, 惊恐, 大笑]));1.加密函数参数分析
我们先给函数打上断点然后刷新网页 和上面的步骤一样还是需要点击三角知道找到我们所需的接口
①.JSON.stringify(i0x)
JSON.stringify() JSON.stringify 是 JavaScript 中的一个全局函数用于将一个 JavaScript 值如 JavaScript 对象或数组转换为 JSON 格式的字符串。这对于将数据保存到文件、在网页之间传递数据、或发送到服务器例如通过 AJAX 请求非常有用因为 JSON 是一种轻量级的数据交换格式易于人阅读和编写同时也易于机器解析和生成。 这个函数的作用就是将i0x转换为json格式 我们点击控制台然后输入i0x就可以得到i0x的值
{rid: R_SO_4_28188263,threadId: R_SO_4_28188263,pageNo: 1,pageSize: 20,cursor: -1,offset: 0,orderType: 1,csrf_token: 71bfd80a0c48b6dbdef22c1499cd480c
}rid与threadId就是歌的id csrf_token是用户的登录状态 剩下的就是关于评论的参数 使用JSON.stringify()函数将i0x转换后我们就得到了第一个参数
②bse6Y([“流泪”, “强”])
第二个参数我们可以看出他是一个函数的返回值他的参数是[“流泪”, “强”]所以我们认为他的值是固定的 我们只需要在控制台输入bse6Y([“流泪”, “强”])就可以得到第二个参数的值 bse6Y([“流泪”, “强”])‘010001’
③bse6Y(Qu1x.md)
首先我们要获取Qu1x.md的值我们直接控制台输入Qu1x.md
[色, 流感, 这边, 弱, 嘴唇, 亲, 开心, 呲牙, 憨笑, 猫, 皱眉, 幽灵, 蛋糕, 发怒, 大哭, 兔子, 星星, 钟情, 牵手, 公鸡, 爱意, 禁止, 狗, 亲亲, 叉, 礼物, 晕, 呆, 生病, 钻石, 拜, 怒, 示爱, 汗, 小鸡, 痛苦, 撇嘴, 惶恐, 口罩, 吐舌, 心碎, 生气, 可爱, 鬼脸, 跳舞, 男孩, 奸笑, 猪, 圈, 便便, 外星, 圣诞]所以bse6Y(Qu1x.md)值也是固定的
bse6Y(Qu1x.md)‘00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7’④.bse6Y([“爱心”, “女孩”, “惊恐”, “大笑”])
和参数二一样他也是一个固定值直接控制台输出
bse6Y([爱心, 女孩, 惊恐, 大笑])0CoJUm6Qyw8W8jud1.加密函数分析
window.asrsea(JSON.stringify(i0x), bse6Y([流泪, 强]), bse6Y(Qu1x.md), bse6Y([爱心, 女孩, 惊恐, 大笑]))我们已经得到了window.asrsea()的参数现在只有找到此函数的源码就可以模拟加密了 我们直接ctrlF搜索window.asrsea 我们直接把这个函数复制下来
!function() {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}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()}function c(a, b, c) {var d, e;return setMaxDigits(131),d new RSAKeyPair(b,,c),e encryptedString(d, a)}function d(d, e, f, g) {var h {}, i a(16);return h.encText b(d, g),h.encText b(h.encText, i),h.encSecKey c(i, e, f),h}function e(a, b, d, e) {var f {};return f.encText c(a e, b, d),f}window.asrsea d,
}();这就是加密函数
五.在本地环境使用此函数
1.直接将js代码复制并用js环境运行
python如何执行js代码: https://blog.csdn.net/python_9k/article/details/138562809 Node.js安装与配置详细步骤: https://blog.csdn.net/qq_42006801/article/details/124830995
2.将js代码翻译为python代码
如果读不懂js代码直接复制给ai来使用
这段JavaScript代码定义了一系列函数用于生成随机字符串、使用AES加密、使用RSA加密以及组合这些加密步骤来形成最终的加密数据。下面是对这些函数及其作用的详细解释
1. a(a)
• 功能生成一个长度为a的随机字符串字符串由字母大小写和数字组成。
• 实现使用Math.random和Math.floor生成随机索引从字符集b中选取字符最终拼接成一个随机字符串。
2. b(a, b)
• 功能使用AES算法加密字符串a密钥是b。
• 实现使用CryptoJS库中的AES加密方法采用CBC模式IV初始化向量固定为0102030405060708加密后返回加密字符串的Base64编码。
3. c(a, b, c)
• 功能使用RSA算法加密字符串a公钥由b和c组成b是公钥的指数c是模数。
• 实现使用RSAKeyPair创建一个RSA公钥然后使用encryptedString方法加密字符串a。
4. d(d, e, f, g)
• 功能组合AES和RSA加密首先使用AES加密d然后对加密后的AES密钥再进行一次AES加密并使用RSA加密生成的随机字符串i。
• 实现
• 生成16位随机字符串i。
• 使用g作为AES密钥加密d。
• 使用i作为新的AES密钥再次加密前一步的输出。
• 使用RSA公钥e和f加密i。
• 返回一个对象包含encText两次AES加密后的结果和encSecKeyRSA加密后的结果。
5. e(a, b, d, e)
• 功能使用RSA算法加密字符串a加上e公钥由b和d组成。
• 实现与c函数相似但是将a e作为要加密的字符串。
6. window.asrsea d
• 功能将d函数绑定到window对象的asrsea属性上使其在全局范围内可用。
加密步骤总结
• 首先生成一个随机字符串i。
• 使用g作为AES密钥加密原始数据d。
• 再次使用i作为AES密钥加密上一步的结果。
• 最后使用RSA公钥加密i生成encSecKey。
• 返回一个包含encText两次AES加密的结果和encSecKeyRSA加密的结果的对象。
这种加密策略通常用于网络请求中尤其是音乐流媒体服务或API接口以保护数据在传输过程中的安全。六.python代码
main.py from Crypto.Cipher import AES
import base64
from Crypto.Util.Padding import pad
import requests
from jiami import Ajimport re
def gdata(decrypt_str):key_str 0CoJUm6Qyw8W8judiv_str 0102030405060708a ouPO61mhRSoLJEwzencrypt_str aes_cbc_encrypt_text(decrypt_str, key_str, iv_str)encrypt_str aes_cbc_encrypt_text(encrypt_str, a, iv_str)return encrypt_strdef idh():name input(请输入歌名: )i1x {csrf_token: ,limit: 8,s: name}data i1xaj Aj(data)url https://music.163.com/weapi/search/suggest/webres requests.post(url, data{params: aj.getparams(data), encSecKey: aj.getenseckey()})return str(res.json()[result][songs][0][id])def aes_cbc_encrypt_text(decrypt_text: str, key: str, iv: str) - str:加密AES_CBC的明文:param decrypt_text: 明文:param key: 密钥:param iv: 密钥偏移量:return: 密文aes2 AES.new(key.encode(utf-8), AES.MODE_CBC, iv.encode(utf-8))encrypt_text aes2.encrypt(pad(decrypt_text.encode(utf-8), AES.block_size, stylepkcs7))encrypt_text str(base64.encodebytes(encrypt_text), encodingutf-8).replace(\n, )return encrypt_textiddidh()
ridR_SO_4_idd# AES_CBC加密模式
decrypt_str {\ids\:\[str(idd)]\,\level\:\standard\,\encodeType\:\aac\}
decrypt_str2{\rid\: \%s\,\threadId\: \%s\,\pageNo\: \1\,\pageSize\: \20\,\cursor\: \-1\,\offset\: \0\,\orderType\: \1\}%(rid,rid)
decrypt_str3{\id\:\%s\,\lv\: \-1\,\tv\:\-1\}%iddparamsgdata(decrypt_str)
params2gdata(decrypt_str2)
params3gdata(decrypt_str3)
encSecKeyc13dc213bd5889986ef8a7af39406c640bf77c6a5a34fe86324b648708b3af49919368a2d555771ea5453a605be7bfeaca0860696a9a9889e24a925bfeb56455f7275e534e733eaa5f94392d7b75da0701b8f38a3006bd6cd10cce66d64daa39f6dd12f970421d79b91abc8116012ee4f2dc8c7648c527abc22158b0338a9171
urlhttps://music.163.com/weapi/song/enhance/player/url/v1?
url2https://music.163.com/weapi/comment/resource/comments/get?
url3https://music.163.com/weapi/song/lyric
data{params: params,
encSecKey: encSecKey
}
data2{
params: params2,
encSecKey: encSecKey
}
data3{
params: params3,
encSecKey: encSecKey
}
resrequests.post(url,datadata)
res2requests.post(url2,datadata2)
res3requests.post(url3,datadata3)
print(评论)
for i in res2.json()[data][comments]:print(i[content])
#print(res.text)
print(___________________________________________________________________)
print(歌曲url:)
print(res.json()[data][0][url])
print(___________________________________________________________________)
print(歌词)
txtres3.json()[lrc]
listre.findall(r\[(.*?)\](.*?)\\n,str(txt),re.S)
for i in list:print(i[1])jiami.py
from Crypto.Cipher import AES
from base64 import b64encode
import jsonclass Aj:g0CoJUm6Qyw8W8judi7HCEonr7xwebMhJVdef __init__(self,data):self.datadatadef getenseckey(self):return 774c6922c77e2d39c9ec18d91210752d86517dee1ab731b3f8a41306ef5b92bc5809105f6cd679375d557dbf59746e1ace6b5a8a313efd70d3c645d198e3e509dbb61776926032eaccfa92c6f5921c8672baf3a2fd5d6d08c1a6869200fbb5e3191902026144060d6e58afcd9ef95f8be592fa80a25791c5b51a1264905026cfdef jiamiAES(self,data, key):# datadata.encode(utf-8)iv 0102030405060708aes AES.new(keykey.encode(utf-8), IViv.encode(utf-8), modeAES.MODE_CBC)bs aes.encrypt(data.encode(utf-8))return str(b64encode(bs), utf-8)def getparams(self,data):data json.dumps(data)data self.to_16(data)t1 self.jiamiAES(data,self.g)t2 self.jiamiAES(self.to_16(t1),self.i)return t2def to_16(self,data):pad 16 - len(data) % 16data chr(pad) * padreturn data