专栏首页AI派[Python爬虫]中国新说唱 Skr~ Skr~

[Python爬虫]中国新说唱 Skr~ Skr~

来源:程序员共成长

https://mp.weixin.qq.com/s/IiLGk1qk9IXv6XD96GODcg

登录https://music.163.com/ 网易云音乐搜索新说唱,打开Chrome的开发工具工具选择Network并重新加载页面,找到与评论数据相关的请求即name为

web?csrf_token=的POST请求,如下图所示

查看该请求的headers我们发现formData包含了两个参数:params、encSecKey。显然这两个参数是经过js加密的,这就是网易云反爬虫的一种策略。如下图:

我们再来看一下请求的Initiator有个core 2ab1b2b..js。因此我们需要分析一下这个js,找出formData加密的规则即可。

将js文件进行格式化,全局搜索params或者encSecKey

params和encSecKey是从bSC8u这个对象中取的

k8c.cE9v({
 params: bSC8u.encText,
 encSecKey: bSC8u.encSecKey
})

而这个对象是由windows.asrsea() 这个方法获得的,定位到该方法。如下图所示:

通过分析代码我们发现 d函数才是最终的出口。分析d函数:

1、通过 a(16) 函数生成一个长度为16的随机字符串

2、encText这个参数通过两次调用 b(a,b) 函数完成,这个函数的作用为AES加密

3、调用 c(i, e, f)得到encSecKey,这个函数的作用是进行RSA加密

AES加密

AES(Advanced Encryption Standard)对称加密算法是一种高级数据加密标准,是美国联邦政府采用的一种区块加密标准,可有效抵制针对DES的攻击算法。特点:密钥建立时间短、灵敏性好、内存需求低、安全性高。

RSA加密

RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。到目前为止,世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长,用RSA加密的信息实际上是不能被解破的。

通过上面分析,除了 i 是一个随机字符串,我们只需要知道d、e、f、g这四个参数就可以构造请求进行后续操作了。接下来我们进行js断点调试。

经过多次调试,我们发现e、f、g这三个值是不变的,唯一改变的是d。再结合上文分析,encSecKey由函数c(i, e, f)得到的,那是不是就意味着encSeckey这个值时不变的呢?

然而,经过代码测试并不是这样,要保证encSecKey和params中的随机字符串(也就是i的值)是一样的才可以。

首先我们先实现函数a,即生成16位的随机字符

#生成随机长度为16的字符串的二进制编码
def random_b():
    seed = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    sa = []
    for i in range(16):
        sa.append(random.choice(seed))
    salt = ''.join(sa)
    return bytes(salt, 'utf-8')
    # 更简单的做法
    # return bytes(''.join(random.sample('1234567890DeepDarkFantasy', 16)), 'utf-8')

其次来实现加密参数的生成(说白了就是翻译js代为为python代码)

#第二参数,rsa公匙组成
pub_key = "010001"
#第三参数,rsa公匙组成
modulus = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
#第四参数,aes密匙
secret_key = b'0CoJUm6Qyw8W8jud'

"""
AES 加密
"""
def aes_encrypt(text, key):
    # 偏移量
    iv = b'0102030405060708'
    # 对长度不是16倍数的字符串进行补全,然后在转为bytes数据
    pad = 16 - len(text) % 16
    try:
        # 如果接到bytes数据(如第一次aes加密得到的密文)要解码再进行补全
        text = text.decode()
    except:
        pass
    text = text + pad * chr(pad)
    try:
        text = text.encode()
    except:
        pass
    encryptor = AES.new(key, AES.MODE_CBC, iv)
    ciphertext = encryptor.encrypt(text)
    ciphertext = base64.b64encode(ciphertext).decode('utf-8')  # 得到的密文还要进行base64编码
    return ciphertext


"""
RSA 加密
"""
def rsa_encrypt(random_char):
    text = random_char[::-1]#明文处理,反序并hex编码
    rsa = int(binascii.hexlify(text), 16) ** int(pub_key, 16) % int(modulus, 16)
    return format(rsa, 'x').zfill(256)

"""
构造params
"""
def aes_param(data):
    text = json.dumps(data)
    random_char = random_b()
    params = aes_encrypt(text, secret_key)#两次aes加密
    params = aes_encrypt(params, random_char)
    enc_sec_key = rsa_encrypt(random_char)
    data = {
        'params': params,
        'encSecKey': enc_sec_key
    }
    return data

最后参数构造完毕,就可以开始咱们的爬虫了 由于RSA是非对称加密,无法通过encSecKey解密出i,没有i也就无法解密params,所以也就只能对每个接口进行断点调试,观察请求的构造。通过实验我发现

搜索歌曲的data为:

data = {"hlpretag": "<span class=\"s-fc7\">",
        "hlposttag": "</span>",
        "s": "中国新说唱",
        "type": "1",
        "offset": "0",
        "total": "true", #仅在页码为0时为true
        "limit": "30",
        "csrf_token": ""
       }

查询歌曲信息的data:

{
    "id": song_id,#歌曲id
    "lv": -1,
    "tv": -1,
    "csrf_token": ""
}

接下来就可以开始写爬虫了 分析网页请求我们发现搜索歌曲的时候响应是在

https://music.163.com/weapi/cloudsearch/get/web?csrf_token=这个请求里响应的

歌词信息由https://music.163.com/weapi/song/lyric?csrf_token=这个请求响应的

ok!!! 万事俱备,开始Coding

"""
请求头
在这里不能将Referer固定写死
因为在搜索歌曲的时候请求的Referer为:https://music.163.com/search/
而查看歌词的时候请求的Referer为:'https://music.163.com/song?id=歌曲id
"""
headers = {
        'Connection': 'keep-alive',
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
        'Host': 'music.163.com',
        'Origin': 'https://music.163.com',
    }



"""
通过歌曲id爬歌词内容
"""
def find_song_word(song_id):
    referer = 'https://music.163.com/song?id=' + song_id
    headers['Referer'] = referer
    url = 'https://music.163.com/weapi/song/lyric?csrf_token='
    param = {"id": song_id, "lv": -1, "tv": -1, "csrf_token": ""}
    data = aes_param(param)
    result = requests.post(url, data=data, headers=headers)
    result = result.json()
    return result['lrc']['lyric']



# mongo服务
client = pymongo.MongoClient('mongodb://127.0.0.1:27017/')
# song数据库
db = client.song
# song_detail表,没有自动创建
detail_db = db.song_detail

if __name__ == '__main__':
    # 搜索歌曲url
    query_url = 'https://music.163.com/weapi/cloudsearch/get/web?csrf_token='
    data = {"hlpretag": "<span class=\"s-fc7\">",
            "hlposttag": "</span>",
            "s": "中国新说唱",
            "type": "1",
            "offset": "0",
            "total": "true",
            "limit": "30",
            "csrf_token": ""
            }
    data = aes_param(data)
    referer = 'https://music.163.com/search/'
    headers['Referer'] = referer
    result = requests.post(query_url, data=data, headers=headers)
    result = result.json()
    songs = result['result']['songs']
    for i in songs:
        songer = []
        # 歌曲id
        song_id = i['id']
        # 歌词
        song_content = find_song_word(str(song_id))
        # 歌曲名
        song_name = i['name']
        song_arr = i['ar']
        # 一首歌可能多人唱, 是个列表 需要遍历
        for k in song_arr:
            song_dict = {'id': k['id'], 'name': k['name']}
            songer.append(song_dict)
        # 存入mongodb
        detail_db.insert({'song_id': song_id, 'name': song_name, 'songer': songer, 'content': song_content})

运行之后查看数据库

现在我们有了Rap歌手的id,从全网爬他们的说唱歌曲还不是so easy

本文分享自微信公众号 - AI派(naodong-open),作者:宇亮

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-10-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python 程序执行时如何显示进度条?

    先来说下 tqdm 的使用场景,工作中有时候会遇到这样的问题,想要将某个任务执行很多次,显而易见,可以使用 for 循环来控制它重复执行很多次。

    abs_zero
  • 还没准备好数据呢,为什么要着急用算法呢

    开始之前,通知下我的读者,随着订阅读者越来越多,为了对读者们负责,有以下几件事情需要告知下:

    abs_zero
  • 吴恩达发布《AI转型指南》:喊话CEO们,AI转型分五步

    https://mp.weixin.qq.com/s/7h0qCIuxAUnxF_S0M1xekw

    abs_zero
  • 17岁高中生自学黑客知识 致台“总统府”官网瘫痪

    台“总统府”、调查局、电信及公务机关网站去年屡遭攻击瘫痪,台湾检调机关在一番调查后发现,攻击是一个叫TWDDoS的网站所为,而犯案主嫌是台南部一名17岁钟姓高中...

    周俊辉
  • 记一次对钓鱼网站的多次渗透

    0x01 首先我们对目标进行目录扫描,发现admin.php 进入发现是后台界面,右击查看网页源码

    天钧
  • 网站排名为什么会下降,是什么原因导致排名下降的

    1、竞争对手,百度搜索看看是否是竞争对手成长的原因,看看首页上有哪些网站,分析一下首页上的网站,然后改变自己的网站优化策略。

    高级优化师
  • 癌症研究不知道做什么?来关注这个数据库,或许可以给你一些思路

    如果做肿瘤研究,不知道做什么基因或者蛋白,也不知道从何处入手?那给你推荐一个数据库,或许可以给你提供一些思路。这个数据库就是:The Pathology Atl...

    DoubleHelix
  • Workerman之GatewayWorker框架 - 在线客服,实时通信

    唐成勇
  • 干货|35张PPT,教你快速成为数据分析师

    本文适合一些想学数据相关的知识,来提升自己产品、运营能力的人。不太适合数据分析师。 一、如何入门互联网数据分析 网站分析是一种能力 对于大部分人互联网从...

    灯塔大数据
  • 【行业】注意!腾讯在Google的AI平台TensorFlow中发现了主要的漏洞

    Google被认为是推动全球AI革命的领导者,但它给开发人员提供的工具可能并不像许多人想象的那么安全。中国社交游戏巨头腾讯的一个安全团队最近声称,它在Googl...

    AiTechYun

扫码关注云+社区

领取腾讯云代金券