問(wèn)答網(wǎng)站怎么做營(yíng)銷網(wǎng)絡(luò)營(yíng)銷與直播電商專業(yè)介紹
python爬蟲(chóng)獲取網(wǎng)易云音樂(lè)評(píng)論歌詞以及歌曲地址
- 一.尋找數(shù)據(jù)接口
- 二.對(duì)負(fù)載分析
- 三.尋找參數(shù)加密過(guò)程
- 1.首先找到評(píng)論的請(qǐng)求包并找到發(fā)起程序
- 2.尋找js加密的代碼
- 四.扣取js的加密源碼
- 1.加密函數(shù)參數(shù)分析
- ①.JSON.stringify(i0x)
- ②bse6Y(["流淚", "強(qiáng)"])
- ③bse6Y(Qu1x.md)
- ④.bse6Y(["愛(ài)心", "女孩", "驚恐", "大笑"])
- 1.加密函數(shù)分析
- 五.在本地環(huán)境使用此函數(shù)
- 1.直接將js代碼復(fù)制并用js環(huán)境運(yùn)行
- 2.將js代碼翻譯為python代碼
- 六.python代碼
一.尋找數(shù)據(jù)接口
評(píng)論
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
二.對(duì)負(fù)載分析
從三個(gè)接口的負(fù)載我們可以得出
data={
params:加密數(shù)據(jù)
encSecKey:加密數(shù)據(jù)
}
所以我們只需要找出這個(gè)兩個(gè)參數(shù)的加密過(guò)程就能模擬請(qǐng)求并得到我們想要的數(shù)據(jù)
三.尋找參數(shù)加密過(guò)程
因?yàn)檫@三個(gè)接口的加密是一樣的這里我們用評(píng)論的接口來(lái)講解
1.首先找到評(píng)論的請(qǐng)求包并找到發(fā)起程序
f12打開(kāi)調(diào)試并且點(diǎn)擊網(wǎng)絡(luò)然后找到對(duì)應(yīng)的包https://music.163.com/weapi/comment/resource/comments/get
點(diǎn)擊發(fā)起程序
2.尋找js加密的代碼
我們先點(diǎn)擊發(fā)起程序的第一個(gè)進(jìn)入到j(luò)s文件中找到請(qǐng)求發(fā)出的地方也就是
send()函數(shù)
先加個(gè)斷點(diǎn)然后刷新頁(yè)面(下圖)
刷新后我們就可以看到調(diào)用棧然后從第一個(gè)往下點(diǎn)一直找到send()(上圖)
找到send()后我們?nèi)∠羟懊娴臄帱c(diǎn)并給send()打上斷點(diǎn)然后再次刷新網(wǎng)頁(yè)(上圖)
這個(gè)url代表的是此次請(qǐng)求發(fā)送的url我們?cè)u(píng)論的url為https://music.163.com/weapi/comment/resource/comments/get所以我們點(diǎn)擊上面的小三角放過(guò)此次請(qǐng)求直至抓取到我們所需的請(qǐng)求(上圖)
我們現(xiàn)在就抓取到了評(píng)論請(qǐng)求的data數(shù)據(jù)等信息我們可以看到此時(shí)的信息還是加密的所以我們要繼續(xù)向前找尋找到它未加密的地方(上圖)
data的加密數(shù)據(jù)在t0x這個(gè)調(diào)用棧前面是沒(méi)有的所以我們就能確定數(shù)據(jù)是在這個(gè)調(diào)用棧中被加密然后我們ctrl+ F 直接搜索params就定位到了加密的函數(shù)
四.扣取js的加密源碼
var bVi6c = window.asrsea(JSON.stringify(i0x), bse6Y(["流淚", "強(qiáng)"]), bse6Y(Qu1x.md), bse6Y(["愛(ài)心", "女孩", "驚恐", "大笑"]));e0x.data = j0x.cr1x({params: bVi6c.encText,encSecKey: bVi6c.encSecKey})
根據(jù)上一步我們找到的源碼我們可以看出
我們所需的兩個(gè)加密數(shù)據(jù) params,encSecKey都是由 bVi6c產(chǎn)生的
bVi6c是由 這個(gè)函數(shù)生成的所以只需要取出這個(gè)函數(shù)的加密過(guò)程就能模擬出我們的加密數(shù)據(jù)
window.asrsea(JSON.stringify(i0x), bse6Y(["流淚", "強(qiáng)"]), bse6Y(Qu1x.md), bse6Y(["愛(ài)心", "女孩", "驚恐", "大笑"]));
1.加密函數(shù)參數(shù)分析
我們先給函數(shù)打上斷點(diǎn)然后刷新網(wǎng)頁(yè)
和上面的步驟一樣還是需要點(diǎn)擊三角知道找到我們所需的接口
①.JSON.stringify(i0x)
JSON.stringify()
JSON.stringify 是 JavaScript 中的一個(gè)全局函數(shù),用于將一個(gè) JavaScript 值(如 JavaScript 對(duì)象或數(shù)組)轉(zhuǎn)換為 JSON 格式的字符串。這對(duì)于將數(shù)據(jù)保存到文件、在網(wǎng)頁(yè)之間傳遞數(shù)據(jù)、或發(fā)送到服務(wù)器(例如通過(guò) AJAX 請(qǐng)求)非常有用,因?yàn)?JSON 是一種輕量級(jí)的數(shù)據(jù)交換格式,易于人閱讀和編寫,同時(shí)也易于機(jī)器解析和生成。
這個(gè)函數(shù)的作用就是將i0x轉(zhuǎn)換為json格式
我們點(diǎn)擊控制臺(tái)然后輸入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是用戶的登錄狀態(tài)
剩下的就是關(guān)于評(píng)論的參數(shù)
使用JSON.stringify()函數(shù)將i0x轉(zhuǎn)換后我們就得到了第一個(gè)參數(shù)
②bse6Y([“流淚”, “強(qiáng)”])
第二個(gè)參數(shù)我們可以看出他是一個(gè)函數(shù)的返回值他的參數(shù)是[“流淚”, “強(qiáng)”]所以我們認(rèn)為他的值是固定的
我們只需要在控制臺(tái)輸入bse6Y([“流淚”, “強(qiáng)”])就可以得到第二個(gè)參數(shù)的值
bse6Y([“流淚”, “強(qiáng)”])=‘010001’
③bse6Y(Qu1x.md)
首先我們要獲取Qu1x.md的值我們直接控制臺(tái)輸入Qu1x.md
['色', '流感', '這邊', '弱', '嘴唇', '親', '開(kāi)心', '呲牙', '憨笑', '貓', '皺眉', '幽靈', '蛋糕', '發(fā)怒', '大哭', '兔子', '星星', '鐘情', '牽手', '公雞', '愛(ài)意', '禁止', '狗', '親親', '叉', '禮物', '暈', '呆', '生病', '鉆石', '拜', '怒', '示愛(ài)', '汗', '小雞', '痛苦', '撇嘴', '惶恐', '口罩', '吐舌', '心碎', '生氣', '可愛(ài)', '鬼臉', '跳舞', '男孩', '奸笑', '豬', '圈', '便便', '外星', '圣誕']
所以bse6Y(Qu1x.md)值也是固定的
bse6Y(Qu1x.md)=‘00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7’
④.bse6Y([“愛(ài)心”, “女孩”, “驚恐”, “大笑”])
和參數(shù)二一樣他也是一個(gè)固定值直接控制臺(tái)輸出
bse6Y(["愛(ài)心", "女孩", "驚恐", "大笑"])='0CoJUm6Qyw8W8jud'
1.加密函數(shù)分析
window.asrsea(JSON.stringify(i0x), bse6Y(["流淚", "強(qiáng)"]), bse6Y(Qu1x.md), bse6Y(["愛(ài)心", "女孩", "驚恐", "大笑"]))
我們已經(jīng)得到了window.asrsea()的參數(shù)現(xiàn)在只有找到此函數(shù)的源碼就可以模擬加密了
我們直接ctrl+F搜索window.asrsea
我們直接把這個(gè)函數(shù)復(fù)制下來(lái)
!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,
}();
這就是加密函數(shù)
五.在本地環(huán)境使用此函數(shù)
1.直接將js代碼復(fù)制并用js環(huán)境運(yùn)行
python如何執(zhí)行js代碼: https://blog.csdn.net/python_9k/article/details/138562809
Node.js安裝與配置(詳細(xì)步驟): https://blog.csdn.net/qq_42006801/article/details/124830995
2.將js代碼翻譯為python代碼
如果讀不懂js代碼直接復(fù)制給ai來(lái)使用
這段JavaScript代碼定義了一系列函數(shù),用于生成隨機(jī)字符串、使用AES加密、使用RSA加密,以及組合這些加密步驟來(lái)形成最終的加密數(shù)據(jù)。下面是對(duì)這些函數(shù)及其作用的詳細(xì)解釋:
1. a(a)
? 功能:生成一個(gè)長(zhǎng)度為a的隨機(jī)字符串,字符串由字母(大小寫)和數(shù)字組成。
? 實(shí)現(xiàn):使用Math.random和Math.floor生成隨機(jī)索引,從字符集b中選取字符,最終拼接成一個(gè)隨機(jī)字符串。
2. b(a, b)
? 功能:使用AES算法加密字符串a(chǎn),密鑰是b。
? 實(shí)現(xiàn):使用CryptoJS庫(kù)中的AES加密方法,采用CBC模式,IV(初始化向量)固定為0102030405060708,加密后返回加密字符串的Base64編碼。
3. c(a, b, c)
? 功能:使用RSA算法加密字符串a(chǎn),公鑰由b和c組成(b是公鑰的指數(shù),c是模數(shù))。
? 實(shí)現(xiàn):使用RSAKeyPair創(chuàng)建一個(gè)RSA公鑰,然后使用encryptedString方法加密字符串a(chǎn)。
4. d(d, e, f, g)
? 功能:組合AES和RSA加密,首先使用AES加密d,然后對(duì)加密后的AES密鑰再進(jìn)行一次AES加密,并使用RSA加密生成的隨機(jī)字符串i。
? 實(shí)現(xiàn):
? 生成16位隨機(jī)字符串i。
? 使用g作為AES密鑰加密d。
? 使用i作為新的AES密鑰再次加密前一步的輸出。
? 使用RSA公鑰(e和f)加密i。
? 返回一個(gè)對(duì)象,包含encText(兩次AES加密后的結(jié)果)和encSecKey(RSA加密后的結(jié)果)。
5. e(a, b, d, e)
? 功能:使用RSA算法加密字符串a(chǎn)加上e,公鑰由b和d組成。
? 實(shí)現(xiàn):與c函數(shù)相似,但是將a + e作為要加密的字符串。
6. window.asrsea = d
? 功能:將d函數(shù)綁定到window對(duì)象的asrsea屬性上,使其在全局范圍內(nèi)可用。
加密步驟總結(jié)
? 首先,生成一個(gè)隨機(jī)字符串i。
? 使用g作為AES密鑰加密原始數(shù)據(jù)d。
? 再次使用i作為AES密鑰加密上一步的結(jié)果。
? 最后,使用RSA公鑰加密i,生成encSecKey。
? 返回一個(gè)包含encText(兩次AES加密的結(jié)果)和encSecKey(RSA加密的結(jié)果)的對(duì)象。
這種加密策略通常用于網(wǎng)絡(luò)請(qǐng)求中,尤其是音樂(lè)流媒體服務(wù)或API接口,以保護(hù)數(shù)據(jù)在傳輸過(guò)程中的安全。
六.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 = '0CoJUm6Qyw8W8jud'iv_str = "0102030405060708"a = "ouPO61mhRSoLJEwz"encrypt_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('請(qǐng)輸入歌名: ')i1x = {'csrf_token': "",'limit': "8",'s': name}data = i1xaj = Aj(data)url = 'https://music.163.com/weapi/search/suggest/web'res = 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, style='pkcs7'))encrypt_text = str(base64.encodebytes(encrypt_text), encoding='utf-8').replace("\n", "")return encrypt_textidd=idh()
rid='R_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\"}'%iddparams=gdata(decrypt_str)
params2=gdata(decrypt_str2)
params3=gdata(decrypt_str3)
encSecKey="c13dc213bd5889986ef8a7af39406c640bf77c6a5a34fe86324b648708b3af49919368a2d555771ea5453a605be7bfeaca0860696a9a9889e24a925bfeb56455f7275e534e733eaa5f94392d7b75da0701b8f38a3006bd6cd10cce66d64daa39f6dd12f970421d79b91abc8116012ee4f2dc8c7648c527abc22158b0338a9171"
url='https://music.163.com/weapi/song/enhance/player/url/v1?'
url2='https://music.163.com/weapi/comment/resource/comments/get?'
url3='https://music.163.com/weapi/song/lyric'
data={'params': params,
'encSecKey': encSecKey
}
data2={
'params': params2,
'encSecKey': encSecKey
}
data3={
'params': params3,
'encSecKey': encSecKey
}
res=requests.post(url,data=data)
res2=requests.post(url2,data=data2)
res3=requests.post(url3,data=data3)
print("評(píng)論:")
for i in res2.json()["data"]["comments"]:print(i["content"])
#print(res.text)
print('___________________________________________________________________')
print("歌曲url:")
print(res.json()['data'][0]['url'])
print('___________________________________________________________________')
print("歌詞:")
txt=res3.json()["lrc"]
list=re.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:g='0CoJUm6Qyw8W8jud'i="7HCEonr7xwebMhJV"def __init__(self,data):self.data=datadef getenseckey(self):return "774c6922c77e2d39c9ec18d91210752d86517dee1ab731b3f8a41306ef5b92bc5809105f6cd679375d557dbf59746e1ace6b5a8a313efd70d3c645d198e3e509dbb61776926032eaccfa92c6f5921c8672baf3a2fd5d6d08c1a6869200fbb5e3191902026144060d6e58afcd9ef95f8be592fa80a25791c5b51a1264905026cf"def jiamiAES(self,data, key):# data=data.encode("utf-8")iv = '0102030405060708'aes = AES.new(key=key.encode("utf-8"), IV=iv.encode("utf-8"), mode=AES.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