• Python JS逆向之Ku狗,实现搜索下载功能(附源码)


    今天用Python来实现一下酷狗JS逆向,实现搜索下载功能

    1、环境使用

    • Python 3.8
    • Pycharm

    2、模块使用

    import hashlib  --> pip install hashlib
    import prettytable as pt --> pip install prettytable
    import requests --> pip install requests
    import time
    import re
    import json
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3、实现思路

    数据来源分析

    1. 明确需求
        - 明确采集网站以及数据内容:
            网址: ku狗音乐网站
            数据: 音频链接 / 音频名称
    
    2. 抓包分析
        - 通过开发者工具进行抓包分析
        I. 打开开发者工具: F12 / 右键点击检查选择network <网络>
        II. 刷新网页: 让数据内容重新加载一遍
        III. 找音频链接地址: 点击媒体 
            音频链接: 
        IV. 分析音频链接地址, 是从哪里来的: 通过关键字搜索找到对应数据包位置
            <数据包接口, 存储音频相关数据信息>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    代码实现步骤

    1. 发送请求, 模拟浏览器对于url地址发送请求
        url地址: 分析得到数据包链接
    2. 获取数据, 获取服务器返回响应数据
        开发者工具: response <响应>
    3. 解析数据, 提取我们需要的数据内容
        数据: 音频链接 / 歌名
    4. 保存数据, 保存音频内容
        对于音频链接发送请求, 获取二进制数据内容 <音频内容>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4、源码展示

    接来下看看源码

    # 导入数据请求模块
    import requests
    # 导入正则表达式模块
    import re
    # 导入json
    import json
    # 导入制表模块
    import prettytable as pt
    import hashlib
    import time
     
    def md5_hash(date, word):
        text = [
        'NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt',
        'appid=1014',
        'bitrate=0',
        'callback=callback123',
        f'clienttime={date}',
        'clientver=1000',
        'dfid=2UHYNz3g5BlC1P5mfH2586l5',
        'filter=10',
        'inputtype=0',
        'iscorrection=1',
        'isfuzzy=0',
        f'keyword={word}',
        'mid=6cff5eec372eb97a1152cedd1d7c9fd5',
        'page=1',
        'pagesize=30',
        'platform=WebFilter',
        'privilege_filter=0',
        'srcappid=2919',
        'token=84444db71f298ea679c54e933acfdbe5065b7e0dd17b6bd7c2384cccde1f45c0',
        'userid=458167322',
        'uuid=6cff5eec372eb97a1152cedd1d7c9fd5',
        'NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt'
            ]
        string = ''.join(text)
        md5 = hashlib.md5()
        md5.update(string.encode('utf-8'))
        signature = md5.hexdigest()
        print(signature)
        return signature
     
     
    date = int(time.time() * 1000)
    key_word = input('请输入你要下载的歌曲/歌手:')
    signature = md5_hash(date=date, word=key_word)
    # 1. 发送请求
    link = 'https://complexsearch.***.com/v2/search/song'
    # 模拟浏览器: headers 请求头 字典数据类型, 构建完整键值对
    headers = {
        'Referer': 'https://www.***.com/',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36',
    }
    # 请求参数
    link_data = {
        'callback': 'callback123',
        'srcappid': '2919',
        'clientver': '1000',
        'clienttime': date,
        'mid': '6cff5eec372eb97a1152cedd1d7c9fd5',
        'uuid': '6cff5eec372eb97a1152cedd1d7c9fd5',
        'dfid': '2UHYNz3g5BlC1P5mfH2586l5',
        'keyword': key_word,
        'page': '1',
        'pagesize': '30',
        'bitrate': '0',
        'isfuzzy': '0',
        'inputtype': '0',
        'platform': 'WebFilter',
        'userid': '458167322',
        'iscorrection': '1',
        'privilege_filter': '0',
        'filter': '10',
        'token': '84444db71f298ea679c54e933acfdbe5065b7e0dd17b6bd7c2384cccde1f45c0',
        'appid': '1014',
        'signature': signature,
    }
    # 发送请求
    response = requests.get(url=link, params=link_data, headers=headers)
    """
    2. 获取数据
    3. 解析数据
    """
    html_data = re.findall('callback123\((.*)', response.text)[0].replace(')', '')
    # 把json字符串, 转成字典数据
    json_data = json.loads(html_data)
    tb = pt.PrettyTable()
    tb.field_names = ['序号', '歌名', '歌手', '专辑', 'ID']
    lis = []
    num = 1
    # for循环遍历
    for index in json_data['data']['lists']:
        dit = {
            '歌名': index['SongName'],
            '歌手': index['SingerName'],
            '专辑': index['AlbumName'],
            'ID': index['EMixSongID'],
        }
        lis.append(dit)
        tb.add_row([str(num), index['SongName'], index['SingerName'], index['AlbumName'], index['EMixSongID']])
        num += 1
     
    print(tb)
     
     
    def save(music_id):
    
        # 请求链接, 数据包链接地址
        url = 'https://wwwapi.***.com/yy/index.php'
        # 请求参数 -> 使用data字典接收请求参数
        data = {
            'r': 'play/getdata',
            # 'callback': 'jQuery1910438191389285846_1693915941407',
            'dfid': '2UHYNz3g5BlC1P5mfH2586l5',
            'appid': '1014',
            'mid': '6cff5eec372eb97a1152cedd1d7c9fd5',
            'platid': '4',
            'encode_album_audio_id': music_id,
            '_': '1693915941408',
        }
        # 发送请求 -> 返回响应对象 
        response = requests.get(url=url, params=data, headers=headers)
    
        # 歌名
        audio_name = response.json()['data']['audio_name']
        # 音频链接
        play_url = response.json()['data']['play_url']
        # 对于音频链接发送请求, 获取二进制数据
        music_content = requests.get(url=play_url, headers=headers).content
        # 保存到本地文件夹 \ 转义字符串
        with open('music\\' + audio_name + '.mp3', mode='wb') as f:
            # 写入内容
            f.write(music_content)
     
        print(play_url, audio_name)
     
    page = input('请输入你想要下载歌曲序号 / 全部下载<0>: ')
    try:
        if page == '0':
            for li in lis:
                save(music_id=li['ID'])
        else:
            save(music_id=lis[int(page)-1]['ID'])
    except Exception as e:
        print('你可能输入有误', e)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146

    5、效果展示

    最后就全部爬取到手了

    担心大家看不懂代码,我特意录制了视频详细讲解,跟代码一起打包好了,文章最后的名片自取即可~

    6、最后

    好了,分享就到这结束,下次见!

  • 相关阅读:
    注册页面对数据进行校验,Ajax的使用-数据唯一性
    (14.1)Zotero常用功能:导入题录、参考文献
    Android——service简单介绍
    Java基础空指针
    Linux命令(88)之echo
    Pycharm run 输出界面控制一行能够输出的元素个数
    有想法就去设计吧!——《好玩的好设计》读书笔记
    react中关于函数调用()与bind this的原因
    基于LSTM算法中文歌词生成
    腾讯云4核8G服务器申请费用多少?性能如何?支持几个人?
  • 原文地址:https://blog.csdn.net/ooowwq/article/details/133184778