日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JAVA网易云热评接口_网易云音乐热评爬虫(一): 反编译加密参数

發(fā)布時間:2023/12/14 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JAVA网易云热评接口_网易云音乐热评爬虫(一): 反编译加密参数 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

由于網(wǎng)易云音樂大部分請求做了混淆加密處理,因此直接用requests請求是行不通。本文以獲取歌曲全部評論為例,通過分析網(wǎng)易云的加密過程,來反編譯構(gòu)造加密參數(shù)。下面主要介紹下用Python實現(xiàn)加密參數(shù)的構(gòu)造,并獲取歌曲的全部評論。

一、了解加密過程

1.1 通過觀察網(wǎng)絡(luò)請求

發(fā)現(xiàn)如下接口包含所要的數(shù)據(jù)。包含該頁最新評論,以及所有熱評

再看它評論的參數(shù),著實讓人有點懵逼

很多人看見這一串字符,可能簡單看下前后接口有沒數(shù)據(jù)就放棄了。好了,不賣關(guān)子。這章分析下整個參數(shù)的加密過程,實現(xiàn)最終模擬請求拿到數(shù)據(jù)。

1.2 找請求參數(shù)

可以看的到,它的參數(shù)有兩個,一個是params,一個是encSecKey并且都是經(jīng)過加密的,我們就要分析它在js中的位置(F12打開source搜索encSecKey)

進(jìn)入js內(nèi)部,經(jīng)過斷點調(diào)試發(fā)現(xiàn)這里就是生成最終參數(shù)的地方

1.3 觀察參數(shù)變化

模擬不同分頁請求,觀察變化。效果如下圖:

對比參數(shù)變化,得出參數(shù)構(gòu)成:

csrf_token :始終空字符串

cursor :第一頁默認(rèn)-1;請求下一頁時該參數(shù)為上一頁最后一條評論時間戳(防止數(shù)據(jù)重復(fù))

offset :移動評論數(shù)

orderType :默認(rèn)1

pageNo :頁碼

pageSize :默認(rèn)20

rid : R_SO_4_ ?+ 歌曲ID

threadId :?R_SO_4_ ?+ 歌曲ID

自此,我們已經(jīng)知道整個參數(shù)的構(gòu)成,接下來就看下網(wǎng)易云是如何進(jìn)行參數(shù)加密的

二、分析加密函數(shù)

通過斷點已經(jīng)知道,下面這段js代碼為我們分析的重點

var bZj0x = window.asrsea(JSON.stringify(i2x), bkk0x(["流淚", "強"]), bkk0x(YS7L.md), bkk0x(["愛心", "女孩", "驚恐", "大笑"]));

e2x.data = j2x.cr3x({

params: bZj0x.encText,

encSecKey: bZj0x.encSecKey

})

只要把bZj0x解出來就ok了,這里主要分析幾個函數(shù)

2.1? JSON.stringify(i2x)

斷點調(diào)制找到i2x返回內(nèi)容

就是上文分析的整個字典參數(shù)

csrf_token: ""

cursor: "1610076350235"

offset: "40"

orderType: "1"

pageNo: "2"

pageSize: "20"

rid: "R_SO_4_1807537867"

threadId: "R_SO_4_1807537867"

2.2?bkk0x函數(shù)

bkk0x(["流淚", "強"]), bkk0x(YS7L.md), bkk0x(["愛心", "女孩", "驚恐", "大笑"]),都用到了同一個函數(shù),這里就看下bkk0x函數(shù)內(nèi)部實現(xiàn)是怎樣的

var bkk0x = function(cJj8b) {

var m2x = [];

j2x.bf2x(cJj8b, function(cJi8a) {

m2x.push(YS7L.emj[cJi8a])

});

return m2x.join("")

}

等同于python寫法

def get_bq_n1x(keys):

m0x = []

for key in keys:

m0x.append(emj[key])

return ''.join(m0x)

YS7L.emj是一個固定的字典

YS7L.emj = {

"色": "00e0b",

"流感": "509f6",

"這邊": "259df",

"弱": "8642d",

"嘴唇": "bc356",

"親": "62901",

"開心": "477df",

"呲牙": "22677",

"憨笑": "ec152",

"貓": "b5ff6",

"皺眉": "8ace6",

"幽靈": "15bb7",

"蛋糕": "b7251",

"發(fā)怒": "52b3a",

"大哭": "b17a8",

"兔子": "76aea",

"星星": "8a5aa",

"鐘情": "76d2e",

"牽手": "41762",

"公雞": "9ec4e",

"愛意": "e341f",

"禁止": "56135",

"狗": "fccf6",

"親親": "95280",

"叉": "104e0",

"禮物": "312ec",

"暈": "bda92",

"呆": "557c9",

"生病": "38701",

"鉆石": "14af6",

"拜": "c9d05",

"怒": "c4f7f",

"示愛": "0c368",

"汗": "5b7a4",

"小雞": "6bee2",

"痛苦": "55932",

"撇嘴": "575cc",

"惶恐": "e10b4",

"口罩": "24d81",

"吐舌": "3cfe4",

"心碎": "875d3",

"生氣": "e8204",

"可愛": "7b97d",

"鬼臉": "def52",

"跳舞": "741d5",

"男孩": "46b8e",

"奸笑": "289dc",

"豬": "6935b",

"圈": "3ece0",

"便便": "462db",

"外星": "0a22b",

"圣誕": "8e7",

"流淚": "01000",

"強": "1",

"愛心": "0CoJU",

"女孩": "m6Qyw",

"驚恐": "8W8ju",

"大笑": "d"

}

YS7L.md是一個固定的數(shù)據(jù)

YS7L.md = ["色", "流感", "這邊", "弱", "嘴唇", "親", "開心", "呲牙", "憨笑", "貓", "皺眉", "幽靈", "蛋糕", "發(fā)怒", "大哭", "兔子", "星星", "鐘情", "牽手", "公雞", "愛意", "禁止", "狗", "親親", "叉", "禮物", "暈", "呆", "生病", "鉆石", "拜", "怒", "示愛", "汗", "小雞", "痛苦", "撇嘴", "惶恐", "口罩", "吐舌", "心碎", "生氣", "可愛", "鬼臉", "跳舞", "男孩", "奸笑", "豬", "圈", "便便", "外星", "圣誕"]

所以整個window.asrsea的參數(shù)都是可以得到的了,下面看下 window.asrsea()查看這個函數(shù)執(zhí)行了什么操作

2.3?window.asrsea()

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

可以看到window.asrsea = d,所以我們要執(zhí)行的就是d這個函數(shù),主要執(zhí)行3個操作

a(16),生成16位隨機數(shù)

進(jìn)行兩次AES加密得到h.encText

通過位移等一系列運算生成h.encSecKey

三、Python實現(xiàn)相同的加密算法

"""

網(wǎng)易云請求參數(shù)反編譯工具

:主要斷點觀察js,改為python實現(xiàn)

"""

emj = {

"色": "00e0b",

"流感": "509f6",

"這邊": "259df",

"弱": "8642d",

"嘴唇": "bc356",

"親": "62901",

"開心": "477df",

"呲牙": "22677",

"憨笑": "ec152",

"貓": "b5ff6",

"皺眉": "8ace6",

"幽靈": "15bb7",

"蛋糕": "b7251",

"發(fā)怒": "52b3a",

"大哭": "b17a8",

"兔子": "76aea",

"星星": "8a5aa",

"鐘情": "76d2e",

"牽手": "41762",

"公雞": "9ec4e",

"愛意": "e341f",

"禁止": "56135",

"狗": "fccf6",

"親親": "95280",

"叉": "104e0",

"禮物": "312ec",

"暈": "bda92",

"呆": "557c9",

"生病": "38701",

"鉆石": "14af6",

"拜": "c9d05",

"怒": "c4f7f",

"示愛": "0c368",

"汗": "5b7a4",

"小雞": "6bee2",

"痛苦": "55932",

"撇嘴": "575cc",

"惶恐": "e10b4",

"口罩": "24d81",

"吐舌": "3cfe4",

"心碎": "875d3",

"生氣": "e8204",

"可愛": "7b97d",

"鬼臉": "def52",

"跳舞": "741d5",

"男孩": "46b8e",

"奸笑": "289dc",

"豬": "6935b",

"圈": "3ece0",

"便便": "462db",

"外星": "0a22b",

"圣誕": "8e7",

"流淚": "01000",

"強": "1",

"愛心": "0CoJU",

"女孩": "m6Qyw",

"驚恐": "8W8ju",

"大笑": "d"

}

md = ["色", "流感", "這邊", "弱", "嘴唇", "親", "開心", "呲牙", "憨笑", "貓", "皺眉", "幽靈", "蛋糕", "發(fā)怒", "大哭", "兔子", "星星", "鐘情", "牽手",

"公雞", "愛意", "禁止", "狗", "親親", "叉", "禮物", "暈", "呆", "生病", "鉆石", "拜", "怒", "示愛", "汗", "小雞", "痛苦", "撇嘴", "惶恐", "口罩",

"吐舌", "心碎", "生氣", "可愛", "鬼臉", "跳舞", "男孩", "奸笑", "豬", "圈", "便便", "外星", "圣誕"]

def get_bq_n1x(keys):

m0x = []

for key in keys:

m0x.append(emj[key])

return ''.join(m0x)

def __get_random_str():

"""

Returns:16位的隨機字符串

"""

str_set = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

random_str = ""

for i in range(16):

index = random.randint(0, len(str_set) - 1)

random_str += str_set[index]

return random_str

arg2 = get_bq_n1x(["流淚", "強"])

arg3 = get_bq_n1x(md)

arg4 = get_bq_n1x(["愛心", "女孩", "驚恐", "大笑"])

random_str = __get_random_str()

def __aes_encrypt(text, key):

"""

獲取到ASW加密后的數(shù)據(jù)

Args:

text: 首先CBC加密方法,text必須位16位數(shù)據(jù)

key: 加密的key

Returns:加密后的字符串

"""

# 加密或者解密的初始向量(16位)

iv = "0102030405060708"

# 不是16的倍數(shù)則填充

pad = 16 - len(text) % 16

if isinstance(text, str):

text = text + pad * chr(pad)

else:

text = text.deocde("utf-8") + pad * chr(pad)

aes = AES.new(key=bytes(key, encoding="utf-8"), mode=2, iv=bytes(iv, encoding="utf-8"))

res = aes.encrypt(bytes(text, encoding="utf-8"))

res = base64.b64encode(res).decode("utf-8")

return res

def __get_enc_text(arg1):

"""

對稱加密后的參數(shù)

Args:

arg1:加密參數(shù)

Returns:

"""

enc_text = __aes_encrypt(arg1, arg4)

enc_text = __aes_encrypt(enc_text, random_str)

return enc_text

def __get_enc_sec_key():

"""

對稱加密密鑰

通過查看js代碼,獲取encSecKey

"""

# 隨機字符串逆序排列

text = random_str[::-1]

rs = int(codecs.encode(text.encode('utf-8'), 'hex_codec'), 16) ** int(arg2, 16) % int(arg3, 16)

return format(rs, 'x').zfill(256)

def linux_encrypt(text):

# print(text)

return text

def get_form_data(text, method=''):

"""

反編譯生成

請求的form-data參數(shù)

Args:

text: 跟蹤js,自己組裝參數(shù)

method: 方法

Returns:form-data參數(shù)

"""

"""

"""

if method == 'linux':

return linux_encrypt(text)

text = str(text)

return {"params": __get_enc_text(text), "encSecKey": __get_enc_sec_key()}

四、模擬請求歌曲評論

只要加密過程知道了,其實很多接口都可以模擬請求,此文僅供學(xué)習(xí)。

最終執(zhí)行效果如下圖:

總結(jié)

以上是生活随笔為你收集整理的JAVA网易云热评接口_网易云音乐热评爬虫(一): 反编译加密参数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。