游贤 成都理工大学信息科学与技术学院
抓取全站信息一般选择有规律的网页采用广度优先方法,考虑到如果从歌单页面开始的话,会有很多歌曲重复,因为相同的歌曲可以划分到不同的歌单。因此最终决定从歌手页面开始,作为种子页面,这样歌曲的重复量会小很多(如果有多个歌手合唱,那么这首歌会出现在每个歌手的歌曲页面当中,他们的访问地址是不一样的)。
方法一: 从http://music.163.com/discover/artist页面出发,可以找到所有的音乐人,
如图所示,每个歌手分类对应的url为http://music.163.com/discover/artist/cat?id=xxx 它 的 可 取 值 有 1001,1002,1003,2001,2002,2003,6001,6002,6003,7001,7002,7003,4001,4002,4003。然后我没随便进入其中其一个页面
网页中的id就是之前提到的id的可取值,这里取1001代表华语男歌手;initial是首字母的意思。这里的65代表A(华语男歌手中姓氏首字母是A的歌手), ASCII码的表示方式,表示,,最后有个其他的分类,用0表示,然后我们继续跟进可以来到歌手的专辑页面和歌曲的详细页面,从而获取到歌曲的下载地址和评论信息。
以杨宗纬的“可惜不是你”这首歌为例子,对应url为music.163.com/song?id-29375071。
打开抓包工具或者浏览器开发者工具,下拉显示评论信息,可以获取到评论的http请求。可以看出这是一个POST的请求,带有params和encSecKey两个参数,这两个参数都是经过加密处理的
这两个参数是经过js加密的,因此我们需要对相应的js文件做断点调试,找到它生成加密参数的函数。利用浏览器开发者工具的全局搜索功能,我们很快就能定位到
var bua = window.asrsea(JSON.stringify(bl), bbZ([‘流泪’,‘强’]), bbZ(Ka.md), bbZ([‘爱心’, ‘女孩’,
‘惊恐’, ‘大笑’]));
bf.data = bm.eX({
params: bua.encText,
encSecKey: bua.encSecKey
}),
可以看出两个加密参数都是在这里生成的。
继续跟进调试发现Window.asrsea 是一个d函数:
其中 e, f,g都是固定的字符:
e: “010001”
f: “””00e0b509f6259df8642dbc35662901477df22677ec152b 5ff68ace615
bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fc cf
695280104e0 312 ecbda92557c93870114af6c9d05c4f7f0c3685b 7a46
bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d5 46b
8e2 89 dc6935b3ece0462db0a22b8e7”””
g: 0CoJUm6Qyw8W8jud
这个函数的功能如下:
1. 先生成一个16位随机数i
2. 使用g参数作为key,将动态参数d进行加密得encText(加密函数b(a,b))
3. 使用随机数i作为key,将上步加密得到的encText再次加密(加密函数b(a,b))
4. 使用参数e,f作为key,将随机数i进行加密的encSecKey(加密函数c(a, b, c))
5. 函数c是一个简单的rsa加密
3.关键代码实现
利用python实现两次aes和一次rsa解密
def create_aes_key(size):
return (''.join([hex(b)[2:] for b in os.urandom(size)]))[0:16]
def aesEncrypt(self, text, key):
iv = '0102030405060708'
pad = 16 - len(text) % 16
text = text + pad * chr(pad)
encryptor = AES.new(key, 2, iv)
ciphertext = encryptor.encrypt(text)
ciphertext = base64.b64encode(ciphertext)
return ciphertext.decode('utf8')
def rsa_encrypt(self, text):
e = '010001'
n = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff 68ace615'
'bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135f ccf'
'695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b 7a46'
'bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d 546b'
'8e289dc6935b3ece0462db0a22b8e7'
reverse_text = text[::-1].encode('utf8')
pub_key = RSA.construct([int(n, 16), int(e, 16)])
encrypt_text = pub_key.encrypt(int(binascii.hexlify(reverse_text), 16), None)[0]
return format(encrypt_text, 'x').zfill(256)