文章目录

  • 前言
  • 一、请求分析
  • 二、逆向思路
  • 三、全部代码
  • 总结

前言

声明:本文章只是用于学习逆向知识,仅供学习,未经作者同意禁止转载

对于爬虫而言,不管是什么类型的都会遵循这几个步骤

  1. 获取目标url
  2. 分析请求数据
  3. 逆向解密数据
  4. 伪造请求
  5. 清洗数据
  6. 保存数据

这是对于逆向爬虫中的步骤。

本文会使用谷歌浏览器自带的开发者工具,分析网页端的酷狗音乐的请求进行逆向。

当然对于手机端也是可以进行爬虫和逆向的,不过会比网页端复杂多,需要一些工具以及反编译手段,需要java部分基础,这个我们将留到后面讲解学习。

一、请求分析

首先我们先进入酷狗音乐的搜索页面:
https://www.kugou.com/yy/html/search.html#searchType=song&searchKeyWord=快乐崇拜
点击第一首歌进去听一下,然后我们看一下当前页面的url如下:
https://www.kugou.com/mixsong/1rkjpr6a.html?fromsearch=快乐崇拜#hash=CA937F42CE9AACC3CDDB2516DAEE55D4&album_id=8437324&album_audio_id=106774479
我们点击f12打开开发者工具进行抓包找到如图:


发现了这里请求是GET并且有我们想要的结果,所以我们可以去分析第一张图的参数

二、逆向思路

经过测试发现该接口只需要midalbum_audio_id两个参数就可以获取到接口了。

那么这个album_audio_id好猜,顾名思义就是这个音乐的id嘛,那么这个mid是个什么呢?

我们可以发现mid是32位的,非常的像md5加密,所以我们去看源代码如图:


通过搜索mid发现了mid调用了一个getBaseInfo函数,那么我们可以往上看找打在哪里引入(
可以抓包找到也可以往上看引用地址
)

如下:

可以看到mid参数确实是个md5,所以我们可以把这两个代码单独拿出来

getBaseInfo.min.js如下:

const Guid = function () {function e() {return (65536 * (1 + Math.random()) | 0).toString(16).substring(1)}return e() + e() + "-" + e() + "-" + e() + "-" + e() + "-" + e() + e() + e()
}
const MD5 = function (e) {function n(e, n) {e[n >> 5] |= 128 << n % 32,e[14 + (n + 64 >>> 9 << 4)] = n;for (var t = 1732584193, s = -271733879, c = -1732584194, u = 271733878, d = 0; d < e.length; d += 16) {var f = t, m = s, g = c, p = u;s = a(s = a(s = a(s = a(s = o(s = o(s = o(s = o(s = r(s = r(s = r(s = r(s = i(s = i(s = i(s = i(s, c = i(c, u = i(u, t = i(t, s, c, u, e[d + 0], 7, -680876936), s, c, e[d + 1], 12, -389564586), t, s, e[d + 2], 17, 606105819), u, t, e[d + 3], 22, -1044525330), c = i(c, u = i(u, t = i(t, s, c, u, e[d + 4], 7, -176418897), s, c, e[d + 5], 12, 1200080426), t, s, e[d + 6], 17, -1473231341), u, t, e[d + 7], 22, -45705983), c = i(c, u = i(u, t = i(t, s, c, u, e[d + 8], 7, 1770035416), s, c, e[d + 9], 12, -1958414417), t, s, e[d + 10], 17, -42063), u, t, e[d + 11], 22, -1990404162), c = i(c, u = i(u, t = i(t, s, c, u, e[d + 12], 7, 1804603682), s, c, e[d + 13], 12, -40341101), t, s, e[d + 14], 17, -1502002290), u, t, e[d + 15], 22, 1236535329), c = r(c, u = r(u, t = r(t, s, c, u, e[d + 1], 5, -165796510), s, c, e[d + 6], 9, -1069501632), t, s, e[d + 11], 14, 643717713), u, t, e[d + 0], 20, -373897302), c = r(c, u = r(u, t = r(t, s, c, u, e[d + 5], 5, -701558691), s, c, e[d + 10], 9, 38016083), t, s, e[d + 15], 14, -660478335), u, t, e[d + 4], 20, -405537848), c = r(c, u = r(u, t = r(t, s, c, u, e[d + 9], 5, 568446438), s, c, e[d + 14], 9, -1019803690), t, s, e[d + 3], 14, -187363961), u, t, e[d + 8], 20, 1163531501), c = r(c, u = r(u, t = r(t, s, c, u, e[d + 13], 5, -1444681467), s, c, e[d + 2], 9, -51403784), t, s, e[d + 7], 14, 1735328473), u, t, e[d + 12], 20, -1926607734), c = o(c, u = o(u, t = o(t, s, c, u, e[d + 5], 4, -378558), s, c, e[d + 8], 11, -2022574463), t, s, e[d + 11], 16, 1839030562), u, t, e[d + 14], 23, -35309556), c = o(c, u = o(u, t = o(t, s, c, u, e[d + 1], 4, -1530992060), s, c, e[d + 4], 11, 1272893353), t, s, e[d + 7], 16, -155497632), u, t, e[d + 10], 23, -1094730640), c = o(c, u = o(u, t = o(t, s, c, u, e[d + 13], 4, 681279174), s, c, e[d + 0], 11, -358537222), t, s, e[d + 3], 16, -722521979), u, t, e[d + 6], 23, 76029189), c = o(c, u = o(u, t = o(t, s, c, u, e[d + 9], 4, -640364487), s, c, e[d + 12], 11, -421815835), t, s, e[d + 15], 16, 530742520), u, t, e[d + 2], 23, -995338651), c = a(c, u = a(u, t = a(t, s, c, u, e[d + 0], 6, -198630844), s, c, e[d + 7], 10, 1126891415), t, s, e[d + 14], 15, -1416354905), u, t, e[d + 5], 21, -57434055), c = a(c, u = a(u, t = a(t, s, c, u, e[d + 12], 6, 1700485571), s, c, e[d + 3], 10, -1894986606), t, s, e[d + 10], 15, -1051523), u, t, e[d + 1], 21, -2054922799), c = a(c, u = a(u, t = a(t, s, c, u, e[d + 8], 6, 1873313359), s, c, e[d + 15], 10, -30611744), t, s, e[d + 6], 15, -1560198380), u, t, e[d + 13], 21, 1309151649), c = a(c, u = a(u, t = a(t, s, c, u, e[d + 4], 6, -145523070), s, c, e[d + 11], 10, -1120210379), t, s, e[d + 2], 15, 718787259), u, t, e[d + 9], 21, -343485551),t = l(t, f),s = l(s, m),c = l(c, g),u = l(u, p)}return Array(t, s, c, u)}function t(e, n, t, i, r, o) {return l(s(l(l(n, e), l(i, o)), r), t)}function i(e, n, i, r, o, a, l) {return t(n & i | ~n & r, e, n, o, a, l)}function r(e, n, i, r, o, a, l) {return t(n & r | i & ~r, e, n, o, a, l)}function o(e, n, i, r, o, a, l) {return t(n ^ i ^ r, e, n, o, a, l)}function a(e, n, i, r, o, a, l) {return t(i ^ (n | ~r), e, n, o, a, l)}function l(e, n) {var t = (65535 & e) + (65535 & n);return (e >> 16) + (n >> 16) + (t >> 16) << 16 | 65535 & t}function s(e, n) {return e << n | e >>> 32 - n}function c(e) {for (var n = Array(), t = (1 << d) - 1, i = 0; i < e.length * d; i += d)n[i >> 5] |= (e.charCodeAt(i / d) & t) << i % 32;return n}function u(e) {for (var n = "", t = 0; t < 4 * e.length; t++)n += "0123456789abcdef".charAt(e[t >> 2] >> t % 4 * 8 + 4 & 15) + "0123456789abcdef".charAt(e[t >> 2] >> t % 4 * 8 & 15);return n}var d = 8;return e = e ? function (e) {return u(n(c(e), e.length * d))}(e) : ""
}function get_mid() {const uid = Guid()return MD5(uid)
}

自此mid就完成了,那么现在我们就需要去找album_audio_id了,对于逆向我们有时候也需要正向的去分析,对于这种音乐id,一般应该是其他页面传过来给我们,我们才能去获取的,所以回到一开始的搜索页面,打开f12开发者工具抓包。

如下:


可以发现在搜索页面抓到了这个请求,还是一样我们开始分析这个参数。

我们可以观察参数cienttime=1670213288633很明显是一个时间戳,而mid和uuid是相同的,并且我们前面已经解析过了不需要分析,经过测试发现dfid是不变参数keyword是我们搜索的名字,其他参数基本是不变的。

不过我们可以发现,此时还有一个参数signature=b1e228e8bbc9175422a38d2b70986d28,这很明显也是md5加密的,不过我们并不知道是怎么加密的,所以需要继续打断点进行解析测试。

我们使用全局搜索signature关键字

如图:


这个infSign.min.js看名字很像,我们点进去看看。


代码是丑化的,我们格式化一下。


我们可以发现这里很可以,明显这个s参数就是md5的盐,我们打开端点进行调试:


可以看到这就是s参数的全部,而我们就只需要把这22个参数使用join函数合并起来再进行md5加密,就完成了。

那么我们可以将现在我们所有的思路转化成python代码进行实现。

三、全部代码

main.py如下:

import json
import asyncio
import requests
import execjs
from hashlib import md5
import time
import threading# 酷狗音乐主函数
class KuGoMusic():def __init__(self, input):self.new_md5 = md5()self.url = "https://complexsearch.kugou.com/v2/search/song"self.headers = {'user-agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36"}mid = self.get_mid()self.child_url = "https://wwwapi.kugou.com/yy/index.php?r=play/getdata&mid={}".format(mid)self.query = ""self.params = ["NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt", "appid=1014", "bitrate=0", "callback=callback123","clienttime={}".format(int(time.time() * 1000)), "clientver=1000","dfid=4XSQkz1mmSGI2XV1Ud1xgR9V", "filter=10", "inputtype=0", "iscorrection=1", "isfuzzy=0","keyword={}".format(input), "mid={}".format(mid), "page=1", "pagesize=30", "platform=WebFilter","privilege_filter=0","srcappid=2919", "token=", "userid=0", "uuid={}".format(mid),"NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt"]self.info = "".join(self.params)self.new_md5.update(self.info.encode(encoding='utf-8'))self.signature = self.new_md5.hexdigest()del self.params[0]del self.params[-1]self.params.append("signature={}".format(self.signature))def get_mid(self):with open('getBaseInfo.min.js', 'r', encoding='utf-8') as f:text = f.read()js_data = execjs.compile(text)mid = js_data.call('get_mid')return mid# 保存音频给你们当练习写(我没写 = =)def with_open(self,url):passdef get_query(self):# self.params.__iter__()for index, item in enumerate(self.params):if len(self.params) - 1 <= index:self.query += itembreakself.query += "{}&".format(item)def getData(self, url):res = requests.get(url, headers=self.headers).json()print(res['data']['audio_name'], res['data']['play_url'], res['data']['album_name'])async def getData2(self, url):loop = asyncio.get_event_loop()# requests模块默认不支持异步操作,所以就使用线程池来配合实现了。future = await loop.run_in_executor(None, requests.get, url, self.headers)res = future.json()print(res['data']['audio_name'], res['data']['play_url'], res['data']['album_name'])def getData_Threads(self, lists):threads = []for row in lists:url_child = self.child_url + "&album_audio_id={}".format(row["ID"])threads.append(threading.Thread(target=self.getData, args=(url_child,)))for thread in threads:# 执行thread.start()for thread in threads:# 结束thread.join()def getData_test(self, lists):for row in lists:url_child = self.child_url + "&album_audio_id={}".format(row["ID"])self.getData(url_child)def getData_async(self, lists):tasks = []for row in lists:url_child = self.child_url + "&album_audio_id={}".format(row["ID"])tasks.append(self.getData2(url_child))loop = asyncio.get_event_loop()loop.run_until_complete(asyncio.wait(tasks))def parse_text(self, text):lists = json.loads(text)['data']['lists']# 多线程# self.getData_Threads(lists)# 普通# self.getData_test(lists)# 协程self.getData_async(lists)def run(self):self.get_query()url = "{0}?{1}".format(self.url, self.query)res = requests.get(url, headers=self.headers)self.parse_text(res.text[12:-2])if __name__ == '__main__':input = input("请输入歌名或歌手: ")kugo = KuGoMusic(input)kugo.run()

总结

不管是逆向还是非逆向,所有爬虫基本上都遵循着这几个步骤,路还漫长还需不断学习,多加练习。

最后

python爬虫实战之逆向分析酷狗音乐相关推荐

  1. Python爬虫案例:爬取酷狗音乐全排行榜歌曲

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理 本次目标 爬取酷狗音乐全站排行榜歌曲 目标地址 https://www.ku ...

  2. python爬虫教程:爬取酷狗音乐,零基础小白也能爬取哦

    本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理 以下文章来源于腾讯云 作者:python学习教程 ( 想要学习Python?Pyt ...

  3. python爬虫教程:爬取酷狗音乐

    本篇针对爬虫零基础的小白,所以每一步骤我都截图并详细解释了,其实我自己看着都啰嗦,归根到底就是两个步骤的请求,还请大佬绕路勿喷. 1.打开酷狗官网,可以看到搜索框,我们要爬取的数据就是搜索歌曲后,酷狗 ...

  4. Java爬虫系列之实战:爬取酷狗音乐网 TOP500 的歌曲(附源码)

    在前面分享的两篇随笔中分别介绍了HttpClient和Jsoup以及简单的代码案例: Java爬虫系列二:使用HttpClient抓取页面HTML Java爬虫系列三:使用Jsoup解析HTML 今天 ...

  5. 爬虫练手项目_酷狗音乐爬取

    酷狗音乐爬虫 前言 分析网站 第一步 第二步 第三步 第四步 准备爬虫 大体框架 获取signature 完整代码 前言 利用暑假闲暇时间学习了一下爬虫,也尝试了几个爬取图片的小项目,但感觉爬取图片有 ...

  6. python爬虫酷狗_python爬虫教程:爬取酷狗音乐,零基础小白也能爬取哦

    本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理 以下文章来源于腾讯云 作者:python学习教程 ( 想要学习Python?Pyt ...

  7. Python爬虫实战02:分析Ajax请求并抓取今日头条街拍

    1 目标网站分析 首先我们打开今日头条网站,搜索 街拍,点击图集,这里每就是我们要爬取的目录,我们称为索引页.1 点开一个标题,进去,称为详情页.2这里面的图是我们所要爬取的.比如这里可以点击图片,共 ...

  8. python爬虫实战——js逆向登录第一篇:鹏华基金

    鹏华基金 鹏华基金 - 登录 https://aj.phfund.com.cn/login.html 小弟不爱写文字(CSDN的编辑器我不会用.),因此大多数以图片为准~各位大佬看官请见谅~ 如果各位 ...

  9. python爬虫实战——运用requests批量下载qq音乐

    python -qq音乐爬取 在学习一段时间后,在视频的讲解下,觉得自己掌握的不错,就开始了这一次的qq音乐的爬取,在爬取的过程中发现了很多问题.知识点掌握的不够,知识点掌握的不熟,例如:正则表达式的 ...

最新文章

  1. Linux疑难杂症解决方案100篇(十)-带你学习提速增效的几个常用 shell 命令
  2. 华为三层交换机路由配置案例_{华为HCNP-RS}三层交换机的配置实例
  3. 联合体(union)和结构体(struct)的区别
  4. android one x3怎么样,618旗舰手机怎么选,看完这篇文章,你就会知道
  5. LeetCode之Next Greater Element I
  6. solution for python can not import local module
  7. 2061:【例1.2】梯形面积【入门题】
  8. 【5003】马遍历问题
  9. 快速入门Flink (7) —— 小白都喜欢看的Flink流处理之DataSources和DataSinks
  10. LeetCode:三数之和
  11. 看我如何破解一台自动售货机
  12. 自媒体平台数据统计分析爬虫之【趣头条】模拟登陆分析详解及数据统计接口详解
  13. 小程序通过三元运算符设置样式
  14. 大数据Clouder专项技能认证课程:Quick BI企业报表制作
  15. Spark内核设计的艺术:架构设计与实现——前言
  16. linux系统编程3—文件存储函数
  17. CentOS7 使用二进制部署 Kubernetes 1.15-1.17集群(均通用,已经尝试,细心)
  18. IE下载附件,文件大小超过10M后 无法下载
  19. Liang-GaRy啃linux书想吐(一)
  20. 安卓开发使用ttf文字_打破限制,自定义MIUI12相册文字水印字体

热门文章

  1. 桌面排版软件Scribus v1.5.5源码编译,使用VS2017+Qt5.12.7环境
  2. EA常见画图(类图、包图、构件图、状态图、顺序图、活动图)
  3. MakeCert CAB压缩 Signcode
  4. 观察 | 回顾 DeFi 中的“蓝筹股”,DeFi 路在何方?
  5. 串口通信协议常用校验计算以及一些常用方法
  6. 高等数学——柱面与旋转曲面
  7. 去哪儿网网页版机票数据
  8. [Excel] excel随机填充内容/文本/数字
  9. python绘图入门
  10. 电脑硬盘为什么叫计算机,为什么女生的电脑总是很卡 原来硬盘是罪魁祸首