网页抓取解密(网易云技能点界面概况静态网页 )

优采云 发布时间: 2021-12-04 12:01

  网页抓取解密(网易云技能点界面概况静态网页

)

  技能点界面概览静态网页

  网易云仍然有一些网页,其网址一般会随着页面变化而变化。您只需要抓取网页进行分析。

  

  动态网页

  但是随着前后端分离的普及,数据分离的好处是显而易见的。越来越多的数据使用ajax渲染。即便如此,网易云的评论也是如此。

  前后端分离刚刚火起来,当时很多网站并没有太多防备的借口。它让很多网站 很容易得到结果。到目前为止,有很多这样的借口。这种网站爬行就是傻瓜式爬行。

  

  但是随着前端技术的发展,接口变得越来越难。拿网易云的评论来说:它的参数很混乱。

  

  这串数字究竟是什么?很多人看到这样的数据会选择放弃。那我给你解开。

  页面分析 step1:查找参数

  可以看到,有两个参数,一个是params,一个是encSecKey,都是加密的。我们必须分析它的来源。F12 开源并搜索 encSckey。

  

  '在这个js里面寻找encSecKey,我发现它在这里。用断点调试后,发现这是最后一个参数的结果。

  

  step2:分析js函数

  这个js有4w多行。如何在4w多行js中找到有用的信息,然后在这里理清思路?

  

  这需要你的抽象和逆向思维。来,我们开始分析。

   var bYc7V = window.asrsea(JSON.stringify(i3x), bkY2x(["流泪", "强"]), bkY2x(VM8E.md), bkY2x(["爱心", "女孩", "惊恐", "大笑"]));

e3x.data = k4o.cz4D({

params: bYc7V.encText,

encSecKey: bYc7V.encSecKey

})

  上面这段代码是源码。我们先不管 JSON.stringify(i3x) 参数是什么,先搞清楚 window.asrsea 是什么。不远处你会发现:

  

  这就是d函数就是所有的数据,方法的根,四个参数d、e、f、g就是我们刚才说的不用管的参数。

  从这个函数是分析:encText是b()函数传递了两次,encSecKey是c()函数之后执行的一个参数。注意i参数的来源是a(16)。网上看看这些函数。

   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

}

  可以发现a(16)是一个随机生成的数,所以我们不需要关心它。而b目前是AES cbc模式加密的。那么我们就知道encText生成的规则了。两次AES cbc加密 偏移量为60708 两个key不同 函数c是RSA加密的三个参数 整体算法流程差不多有点了解了。

  暂时停在这里,不分析函数,我们在分析数据。

  step3:分析参数

  返回 var bYc7V = window.asrsea(JSON.stringify(i3x), bkY2x(["流泪", "强"]), bkY2x(VM8E.md), bkY2x(["爱心", "girl", "horrified ", "Laughing"])) 这个函数。直觉上我能感觉到有些数据肯定和我们的核心参数没有关系,顶多跟时间戳有关。

  找到bky2x的来源,

  

  再去寻找,其实是没有必要的。寻找这种功能。可以复制到vscode中查找根本原因。分析,这里就不一一介绍了。只是中断分析!看看他是如何执行的。

  

  其实抓多次就会发现最后三个参数是固定的(非交互数据)。

  然而,我最想要的是第一个参数

  

  你心里的参数是这样的,所以和预期的差不多,只有第一个参数和我们的参数有关。offset是page*20,R_SO_4_songid是当前歌曲的id。其实这时候你的i和encSecKey就可以一起保存了。因为上面分析说这个i是随机生成的,encSecKey和我们的核心参数无关,而是和i有关,所以我们需要记录一个组。用作 ESA 加密参数和 post 请求参数。

  你现在是不是很兴奋,因为我真的很想浮出水面。

  第4步:检查

  这一步也是很重要的一个环节,因为你会在它的js里面找到。

  

  网易会做些什么吗?下载原创js进行测试。找到了哈哈,结果是一致的。那么就不需要再次更改该加密算法的代码。

  架构图是

  

  step5:转换为python代码

  AES的cbc模式的代码需要用Python克隆。达到加密的效果,测试一下。发现同样的结果很好

  

  编写爬虫

  让我们开始编写一个爬虫。首先使用邮递员测试这些参数。

  

  没问题,写个爬虫。根据你喜欢的兄弟。输入id生成你的爱字云!每个人的美好时光!

  import requests

import urllib.parse

import base64

from wordcloud import WordCloud

import jieba.analyse

import matplotlib.pyplot as plt

from bs4 import BeautifulSoup

from Crypto.Cipher import AES

header={'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36',

#'Postman-Token':'4cbfd1e6-63bf-4136-a041-e2678695b419',

"origin":'https://music.163.com',

#'referer':'https://music.163.com/song?id=1372035522',

#'accept-encoding':'gzip,deflate,br',

'Accept':'*/*',

'Host':'music.163.com',

'content-lenth':'472',

'Cache-Control':'no-cache',

'content-type': 'application/x-www-form-urlencoded',

'Connection':'keep-alive',

#'Cookie':'iuqxldmzr_=32; _ntes_nnid=a6f29f40998c88c693bc910331bd6bea,1558011234325; _ntes_nuid=a6f29f40998c88c693bc910331bd6bea; _ga=GA1.2.2120707788.1559308501; WM_TID=pV2C%2BjTrRwBBAAERUVJojniTwk8%2B8Zta; JSESSIONID-WYYY=nvf%2BggodQRfcT%2BTvBRmANqMrsDeQCxRvqwFsxDr3eJvNNWhGYFhfCXKFkfAfOdbHhpCsMzT39mAeJ7ZamBQZbiwwtnSZD%5CPWRqKxD9t6dGKD3bTVjomjgB39DB07RNIWI32bYKa2H4fg1qQgqI%2FR%2B%2Br%2BZXJvgFg1Vh%2FA2XRj9S4p0EMu%3A1560927288799; WM_NI=DthwcEQf5Ew2NbTIZmSNhSnm%2F8VWsg5RxhkYogvs2luEwZ6m5UhdzbHYPIr654ZBWKV4o22%2BEwb9BvdLS%2BFOmOAEUG%2B8xd8az4CX%2FiAL%2BZkz3syA0onCPkhQwCtL4pkUcjg%3D; WM_NIKE=9ca17ae2e6ffcda170e2e6eed2d650989c9cd1d*敏*感*词*bb6b88eb2c84e979f9aaff773afb6fb83d950bcb19ecce92af0fea7c3b92a88aca898e24f93bafba6f63a8ebe9caad9679192a8b4ed67ede89ab8f26df78eb889ea53adb9ba94b168b79bb9bbb567f78ba885f96a8c87a0aaf13ef7ec96a3d64196eca1d3b12187a9aedac17ea8949dccc545af918fa6d84de9e8b885bb6bbaec8db9ae638394e5bbea72f1adb7a2b365ae9da08ceb5bb59dbcadb77ca98bad8be637e2a3'

}

def pkcs7padding(text):

"""

明文使用PKCS7填充

最终调用AES加密方法时,传入的是一个byte数组,要求是16的整数倍,因此需要对明文进行处理

:param text: 待加密内容(明文)

:return:

"""

bs = AES.block_size # 16

length = len(text)

bytes_length = len(bytes(text, encoding='utf-8'))

# tips:utf-8编码时,英文占1个byte,而中文占3个byte

padding_size = length if(bytes_length == length) else bytes_length

padding = bs - padding_size % bs

# tips:chr(padding)看与其它语言的约定,有的会使用''

padding_text = chr(padding) * padding

return text + padding_text

def encrypt(key, content):

"""

AES加密

key,iv使用同一个

模式cbc

填充pkcs7

:param key: 密钥

:param content: 加密内容

:return:

"""

key_bytes = bytes(key, encoding='utf-8')

iv = bytes('0102030405060708', encoding='utf-8')

cipher = AES.new(key_bytes, AES.MODE_CBC, iv)

# 处理明文

content_padding = pkcs7padding(content)

# 加密

encrypt_bytes = cipher.encrypt(bytes(content_padding, encoding='utf-8'))

# 重新编码

result = str(base64.b64encode(encrypt_bytes), encoding='utf-8')

return result

def getcomment(songid,page):

url="https://music.163.com/weapi/v1/resource/comments/R_SO_4_"+songid+"?csrf_token="

print(url)

formdata = {

"params": "",

"encSecKey": "c81160c64a08feb6cfed91c1619d5bffd05dd278b685c94a748689edf035ee0436b66aa7019927ce0fedd26aee9a22cdc6743e58a120f9db0126ebb2e61dae3f7ee21088eb747f829bceed9a5bbb9ee7a2eecf1a358fea*敏*感*词*31acaab17c95b8491a6a955f7c17a02a3e7886390c2cb3b981f4ccbd5163a566d27ace95db073401",

}

aes_key = '0CoJUm6Qyw8W8jud'## 不变的

print('aes_key:' + aes_key)

# 对英文加密

source_en = '{"rid":"R_SO_4_'+songid+'","offset":"'+str(page*20)+'","total":"false","limit":"20","csrf_token":""}'

#offset自己该

print(source_en)

encrypt_en = encrypt(aes_key, source_en)#第一次加密

print(encrypt_en)

aes_key='3Unu7SzdXGctW1vA'

encrypt_en = encrypt(aes_key, str(encrypt_en)) # 第二次加密

print(encrypt_en)

formdata['params']=encrypt_en

print(formdata['params'])

formdata = urllib.parse.urlencode(formdata).encode('utf-8')

print(formdata)

req = requests.post(url=url, data=formdata, headers=header)

return req.json()

if __name__ == '__main__':

songid='346576'

page=0

text=''

for page in range(10):

comment=getcomment(songid,page)

comment=comment['comments']

for va in comment:

print (va['content'])

text+=va['content']

ags = jieba.analyse.extract_tags(text, topK=50) # jieba分词关键词提取,40个

print(ags)

text = " ".join(ags)

backgroud_Image = plt.imread('tt.jpg') # 如果需要个性化词云

wc = WordCloud(background_color="white",

width=1200, height=900,

mask=backgroud_Image, # 设置背景图片

#min_font_size=50,

font_path="simhei.ttf",

max_font_size=200, # 设置字体最大值

random_state=50, # 设置有多少种随机生成状态,即有多少种配色方案

) # 字体这里有个坑,一定要设这个参数。否则会显示一堆小方框wc.font_path="simhei.ttf" # 黑体

# wc.font_path="simhei.ttf"

my_wordcloud = wc.generate(text)

plt.imshow(my_wordcloud)

plt.axis("off")

plt.show() # 如果展示的话需要一个个点

file = 'image/' + str("aita") + '.png'

wc.to_file(file)

  

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线