Python JS逆向之酷狗,实现搜索下载功能
今天用Python来实现一下酷狗JS逆向,实现搜索下载功能(附源码)
- Python 3.8
- Pycharm
import hashlib --> pip install hashlib
import prettytable as pt --> pip install prettytable
import requests --> pip install requests
import time
import re
import json
数据来源分析
1. 明确需求
- 明确采集网站以及数据内容:
网址: ku狗音乐网站
数据: 音频链接 / 音频名称
2. 抓包分析
- 通过开发者工具进行抓包分析
I. 打开开发者工具: F12 / 右键点击检查选择network <网络>
II. 刷新网页: 让数据内容重新加载一遍
III. 找音频链接地址: 点击媒体 <media>
音频链接:
IV. 分析音频链接地址, 是从哪里来的: 通过关键字搜索找到对应数据包位置
<数据包接口, 存储音频相关数据信息>
代码实现步骤
1. 发送请求, 模拟浏览器对于url地址发送请求
url地址: 分析得到数据包链接
2. 获取数据, 获取服务器返回响应数据
开发者工具: response <响应>
3. 解析数据, 提取我们需要的数据内容
数据: 音频链接 / 歌名
4. 保存数据, 保存音频内容
对于音频链接发送请求, 获取二进制数据内容 <音频内容>
接来下看看源码
# 导入数据请求模块 import requests # 导入正则表达式模块 import re # 导入json import json # 导入制表模块 import prettytable as pt import hashlib import time # 担心大家看不懂代码,我特意录制了视频详细讲解 # 跟代码一起打包好放在这个抠裙了 592539176 ~ 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.kugou.com/v2/search/song' # 模拟浏览器: headers 请求头 字典数据类型, 构建完整键值对 headers = { 'Referer': 'https://www.kugou.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.kugou.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 [200]> 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)
最后就全部爬取到手了
好了,分享就到这结束,下次见!