python爬虫网易云音乐最热评论并分析_网易云音乐热门评论api分析
網(wǎng)上有現(xiàn)成的例子我就扒過(guò)來(lái)了!!
title: 網(wǎng)易云評(píng)論api分析
date: 2018-12-24 20:54:46
tags: [python]
網(wǎng)易云音樂(lè)是個(gè)好地方,里面各個(gè)都是人才,特別是評(píng)論區(qū)……
所以我就想把評(píng)論爬下來(lái)看看,下面記錄一下分析api的過(guò)程與結(jié)果。
過(guò)程大概如下:
定位到獲取評(píng)論的請(qǐng)求
分析評(píng)論請(qǐng)求方式
用python獲取評(píng)論
定位評(píng)論請(qǐng)求
廢話少說(shuō),F12,在網(wǎng)頁(yè)中隨便找一首歌,url形如: https://music.163.com/#/song?id=28828076,抓包。
待頁(yè)面加載完成之后,隨便找條評(píng)論搜索,定位到獲取評(píng)論的那條請(qǐng)求,如下圖:
可以看到這條請(qǐng)求是發(fā)向https://music.163.com/weapi/v1/resource/comments/R_SO_4_28828076?csrf_token=的,而其中的R_SO_4_后面其實(shí)就是歌曲的id。
分析請(qǐng)求
請(qǐng)求中發(fā)送的數(shù)據(jù)如下圖,看一眼,啥都看不懂,肯定是加密過(guò)了。
從表單中的名稱猜測(cè)出一個(gè)是加密后的內(nèi)容,另一個(gè)是加密密鑰。
下面要找到在哪里加密的信息,然后進(jìn)一步找到加密方法,這樣我們就可以用爬蟲(chóng)來(lái)模擬了。
在哪加密
同樣,在network tab下面搜索encSecKey,搜到了一個(gè)js文件中的兩個(gè)函數(shù)都有encSecKey。
下面列出這兩個(gè)函數(shù):
函數(shù)一
! function() {
function a(a) {
// 獲取隨機(jī)串
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
}
// a是待加密數(shù)據(jù),b是passphrase
function b(a, b) {
var c = CryptoJS.enc.Utf8.parse(b),
d = CryptoJS.enc.Utf8.parse("0102030405060708"),
e = CryptoJS.enc.Utf8.parse(a),
// 使用AES加密
// e是待加密信息
// c是passphrase
// d是nonce
f = CryptoJS.AES.encrypt(e, c, {
iv: d,
mode: CryptoJS.mode.CBC
});
return f.toString()
}
// 生成RSA密鑰對(duì)
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) {
// d是表單數(shù)據(jù)
// e和g是常數(shù)
// 經(jīng)過(guò)分析e: 010001
// g: 0CoJUm6Qyw8W8jud
var h = {},
i = a(16); // 長(zhǎng)度為16的隨機(jī)串
// 上面的b函數(shù)是用于AES加密,這里調(diào)用b進(jìn)行了兩次AES加密
// 使用
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.ecnonasr = e
}();
函數(shù)二
(function() {
var c9h = NEJ.P,
et2x = c9h("nej.g"),
v9m = c9h("nej.j"),
k9b = c9h("nej.u"),
Xw8o = c9h("nm.x.ek"),
l9c = c9h("nm.x");
if (v9m.bl9c.redefine) return;
window.GEnc = true;
var brK4O = function(cxx0x) {
var m9d = [];
k9b.be9V(cxx0x, function(cxv0x) {
m9d.push(Xw8o.emj[cxv0x])
});
return m9d.join("")
};
var cxt0x = v9m.bl9c;
v9m.bl9c = function(Y9P, e9f) {
var i9b = {},
e9f = NEJ.X({}, e9f),
mt4x = Y9P.indexOf("?");
if (window.GEnc && /(^|\.com)\/api/.test(Y9P) && !(e9f.headers && e9f.headers[et2x.Cf0x] == et2x.Gl1x) && !e9f.noEnc) {
if (mt4x != -1) {
i9b = k9b.hb3x(Y9P.substring(mt4x + 1));
Y9P = Y9P.substring(0, mt4x)
}
if (e9f.query) {
i9b = NEJ.X(i9b, k9b.fP2x(e9f.query) ? k9b.hb3x(e9f.query) : e9f.query)
}
if (e9f.data) {
i9b = NEJ.X(i9b, k9b.fP2x(e9f.data) ? k9b.hb3x(e9f.data) : e9f.data)
}
i9b["csrf_token"] = v9m.gO3x("__csrf");
Y9P = Y9P.replace("api", "weapi");
e9f.method = "post";
delete e9f.query;
var bVs3x = window.asrsea(JSON.stringify(i9b), brK4O(["流淚", "強(qiáng)"]), brK4O(Xw8o.md), brK4O(["愛(ài)心", "女孩", "驚恐", "大笑"]));
e9f.data = k9b.cB0x({
params: bVs3x.encText,
encSecKey: bVs3x.encSecKey
})
}
cxt0x(Y9P, e9f)
};
v9m.bl9c.redefine = true
})();
函數(shù)二調(diào)用了window.asrsea,而window.asrsea又在函數(shù)一中被賦值為d。
加密參數(shù)
在window.asrsea的參數(shù)表中,發(fā)現(xiàn)有兩個(gè)硬編碼的列表經(jīng)過(guò)某個(gè)函數(shù)轉(zhuǎn)換后傳入到window.asrsea,也就是傳入到d中,在d打下斷點(diǎn),發(fā)現(xiàn)經(jīng)過(guò)轉(zhuǎn)換后的傳入到d中的參數(shù)如下:
d: "{"ids":"[5113327]","br":128000,"csrf_token":""}"
e: "010001"
f: "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
g: "0CoJUm6Qyw8W8jud"
現(xiàn)在兩個(gè)常數(shù)e,g都已經(jīng)確定了,經(jīng)過(guò)多次斷點(diǎn),發(fā)現(xiàn)f竟然也是常數(shù)。
那么現(xiàn)在傳入加密函數(shù)d中的所有參數(shù)都已經(jīng)確定了,接下來(lái)要分析出來(lái)怎么用這些參數(shù)加密數(shù)據(jù),然后發(fā)送到服務(wù)器。
加密策略
加密策略是使用AES加密請(qǐng)求數(shù)據(jù),然后用RSA加密AES密鑰,我嘗試分析了一下,發(fā)現(xiàn)分析得頭皮發(fā)麻,后面在github找到了。。。。。鏈接在這:網(wǎng)易云新版webapi分析
代碼
代碼是python2寫的,改了一下,python3能用:
import requests
import os
import binascii
import base64
import requests
import json
from Crypto.Cipher import AES
modulus = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'
nonce = b'0CoJUm6Qyw8W8jud'
pubKey = '010001'
"""
加密過(guò)程
隨機(jī)生成加密密鑰secKey
然后用secKey兩次對(duì)post的查詢數(shù)據(jù)進(jìn)行兩次AES加密
用RSA對(duì)secKey加密
最后把加密后的secKey和查詢數(shù)據(jù)post到服務(wù)器
"""
def createSecretKey(size):
return binascii.hexlify(os.urandom(size))[:16]
def aesEncrypt(text, secKey):
pad = 16 - len(text) % 16
text = text + pad * str(chr(pad))
encryptor = AES.new(secKey, AES.MODE_CBC, '0102030405060708'.encode('utf8'))
ciphertext = encryptor.encrypt(text.encode('utf8'))
ciphertext = base64.b64encode(ciphertext).decode('utf8')
return ciphertext
def rsaEncrypt(text, pubKey, modulus):
text = text[::-1]
rs = int(bytes.hex(text), 16) ** int(pubKey, 16) % int(modulus, 16)
return format(rs, 'x').zfill(256)
def encrypted_request(text):
text = json.dumps(text)
secKey = createSecretKey(16)
encText = aesEncrypt(aesEncrypt(text, nonce), secKey)
encSecKey = rsaEncrypt(secKey, pubKey, modulus)
data = {
'params': encText,
'encSecKey': encSecKey
}
return data
def load_headers(filename):
headers = {}
with open(filename, 'r') as f:
for line in f.readlines():
entry = line.split(':', 1)
if len(entry) != 2:
continue
headers[entry[0].strip()] = entry[1].strip()
return headers
def comment_post_url(song_id, csrf=''):
return 'https://music.163.com/weapi/v1/resource/comments/R_SO_4_' + \
song_id + '?csrf_token=' + csrf
if __name__ == '__main__':
# 加載請(qǐng)求頭
headers = load_headers('headers')
song_id = '28828074'
req = {
"csrf_token":"",
"limit":"20",
"offset":"0",
"rid":"R_SO_4_" + song_id,
"total":"true"
}
url = comment_post_url(song_id)
postdata = encrypted_request(req)
print('sending to {}'.format(url))
r = requests.post(url, data=postdata, headers=headers)
print(r.text)
經(jīng)過(guò)測(cè)試Cookies中只有帶有_ntes_nuid就行了。
headers:
Host: music.163.com
Connection: keep-alive
Origin: https://music.163.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/71.0.3578.80 Chrome/71.0.3578.80 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: */*
Referer: https://music.163.com/song?id=558290126
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,en-GB;q=0.6
Cookie: _ntes_nuid=9ae4bf42cfdf19018c7b461442deffe2
參考資料
總結(jié)
以上是生活随笔為你收集整理的python爬虫网易云音乐最热评论并分析_网易云音乐热门评论api分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 关于左位移,右位移
- 下一篇: 《Python深度学习从零开始学》简介