python爬虫实战之逆向分析酷狗音乐

news2024/11/17 1:40:33

文章目录

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


前言

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

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

  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):
		pass
    def get_query(self):
        # self.params.__iter__()
        for index, item in enumerate(self.params):
            if len(self.params) - 1 <= index:
                self.query += item
                break
            self.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()

总结

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

最后

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/63672.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法日常训练12.5

首先有个很大的进步&#xff0c;看见困难题我没选择做逃兵跑路&#xff0c;这点起码是进步了&#xff0c;虽然算法能力还是那么拉&#xff0c;但是起码敢不自量力地分析一下。。。还能看题解理解下。 先找题解中最简单地一种超时方法开始理解&#xff0c;使用动态规划&#xff…

线程基础概念

1.线程基础 现代软件系统中&#xff0c;除了进程之外&#xff0c;线程也是一个十分重要的概念。特别是随着CPU频率增长开始出现停滞&#xff0c;而开始向多核方向发展。多线程&#xff0c;作为实现软件并发执行的一个重要的方法&#xff0c;也开始具有越来越重要的地位。 什么…

[本人毕业设计] 别踩白块_计算机科学与技术_前端H5游戏毕设

摘 要 本文详细介绍了网页版躲避白色钢琴块音乐游戏的设计和实现。由于游戏软件安装占据较大的空间与安装时间&#xff0c;而且步骤繁琐&#xff0c;用常规的游戏安装方法不能取得便捷的游戏安装体验。网页游戏是一种基于在网络游戏中被广泛应用&#xff0c;网页游戏更具有便捷…

【Tensorflow深度学习】实现手写字体识别、预测实战(附源码和数据集 超详细)

需要源码和数据集请点赞关注收藏后评论区留言私信~~~ 一、数据集简介 下面用到的数据集基于IAM数据集的英文手写字体自动识别应用&#xff0c;IAM数据库主要包含手写的英文文本&#xff0c;可用于训练和测试手写文本识别以及执行作者的识别和验证&#xff0c;该数据库在ICDAR1…

对副业的选择无论是自媒体还是 Python接单 ,始终绕不开IT行业。

前言 这个年代&#xff0c;成年人的日子活成了一部苦情戏。十年前&#xff0c;5000块钱工资还能过的自由自在&#xff1b;今天&#xff0c;估计连车贷&#xff0c;房贷&#xff0c;信用卡都不够还。所以一些想要改变现状的朋友&#xff0c;选择了副业这种形式&#xff0c;副业…

【Linux】Shell脚本详解

目录一.概述二.Linux提供的Shell解析器三.Shell入门1.执行一个简单的shell脚本2.脚本常用的执行方法四.变量1.系统预定义变量2.自定义变量3.特殊变量五.运算符六.条件判断1.单条件判断2.多条件判断七.流程控制(重点)1.if判断2.case语句3.for循环4.while循环八.read读取控制台输…

【论文简述】 Point-MVSNet:Point-Based Multi-View Stereo Network(ICCV 2019)

一、论文简述 1. 第一作者&#xff1a;Rui Chen、Songfang Han 2. 发表年份&#xff1a;2019 3. 发表期刊&#xff1a;ICCV 4. 关键词&#xff1a;MVS、深度学习、点云、迭代改进 5. 探索动机&#xff1a;很多传统方法通过多视图光度一致性和正则化优化迭代更新&#xff…

C语言实例|使用C程序优雅地杀掉其它程序进程

C语言文章更新目录 C语言学习资源汇总&#xff0c;史上最全面总结&#xff0c;没有之一 C/C学习资源&#xff08;百度云盘链接&#xff09; 计算机二级资料&#xff08;过级专用&#xff09; C语言学习路线&#xff08;从入门到实战&#xff09; 编写C语言程序的7个步骤和编程…

FPGA 20个例程篇:18.SD卡存放音频WAV播放(中)

第七章 实战项目提升&#xff0c;完善简历 18.SD卡存放音频WAV播放&#xff08;中&#xff09; 如图1所示是WM8731中11个寄存器功能说明概况图&#xff0c;我们需要对照手册&#xff0c;再去深入了解WM8731中的11个寄存器&#xff0c;怎么去配置这些寄存器达到预期的效果&…

了解3dmax坐标系

3dmax具有多种坐标系&#xff0c;其类别如下&#xff1b;默认的是View坐标系&#xff1b; 新建一个茶壶&#xff0c;此时默认是View坐标系&#xff1b; 切换到屏幕坐标系&#xff0c;看一下如下图&#xff1b;要保持视口区域激活&#xff1b; 根据资料&#xff0c;屏幕坐标系&a…

园区如何快速实现数据可视化分析?

对于园区运营方来说&#xff0c;如果没有专业针对性的管理方案以及管理系统辅助的话&#xff0c;实现园区可视化管理的难度非常大&#xff0c;而且操作成本会很高。但如果园区运营方选择引进快鲸智慧楼宇推出的园区数据孪生可视化管理系统的话就会简单很多。 快鲸智慧楼宇数据孪…

视频学习|Springboot在线学习系统

作者主页&#xff1a;编程千纸鹤 作者简介&#xff1a;Java、前端、Pythone开发多年&#xff0c;做过高程&#xff0c;项目经理&#xff0c;架构师 主要内容&#xff1a;Java项目开发、毕业设计开发、面试技术整理、最新技术分享 收藏点赞不迷路 关注作者有好处 文末获得源码 …

对文本进行情感分析(分类)snownlp模块

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 对文本进行情感分析(分类) snownlp模块 选择题 对于以下python代码表述错误的一项是? from snownlp import SnowNLP myText我爱学python&#xff01; print("【显示】text"…

艾美捷ICT FLICA天冬氨酸蛋白酶(Caspase)活性检测试剂盒说明书

Caspases在细胞凋亡和炎症中发挥重要作用。艾美捷ICT FLICA天冬氨酸蛋白酶&#xff08;Caspase&#xff09;活性检测试剂盒被研究人员用于通过培养的细胞和组织中的胱天蛋白酶活性来定量凋亡。用FAM FLICA caspase-1测定试剂盒检测caspase-1活性。该体外试验使用荧光抑制剂探针…

[附源码]计算机毕业设计JAVA音乐网站

[附源码]计算机毕业设计JAVA音乐网站 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven…

一步登顶还是步步维艰?Java 资深架构师撰下的“阿里 P7 成神之路”

很多刚接触到 Java 开发的程序员都以为 Java 资深开发工程师就已经是 Java 开发的顶了&#xff0c;或者是不清楚架构师是干什么的。 举个例子说吧&#xff1a; 房屋建造。 架构师们根据房屋造型的需求设计出适合的构造&#xff0c;然后再反复测算这个框架搭建的可行性&#…

C++文件操作

文章目录计算机文件到底是什么&#xff08;通俗易懂&#xff09;&#xff1f;C文件类&#xff08;文件流类&#xff09;及用法详解C open 打开文件&#xff08;含打开模式一览表&#xff09;使用 open 函数打开文件使用流类的构造函数打开文件文本打开方式和二进制打开方式的区…

Jetson nano 系统安装

ContentsJetson Nano在 EMMC 上安装镜像U 盘启动和 TF 卡启动U 盘启动 (复制 eMMC 上系统)TF 卡启动设置远程登录系统SDK 安装使用 SDK Manager 安装使用指令安装Linux 操作基础文件传输、系统备份风扇配置IMX219-83 Stereo CameraAI 环境搭建PIP3 安装安装机器学习领域重要的安…

MOSFET 和 IGBT 栅极驱动器电路的基本原理学习笔记(二)栅极驱动参考

栅极驱动参考 1.PWM直接驱动 2.双极Totem-Pole驱动器 3.MOSFET Totem-Pole驱动器 4.速度增强电路 5.dv/dt保护 1.PWM直接驱动 在电源应用中&#xff0c;驱动主开关晶体管栅极的最简单方法是利用 PWM 控制其直接控制栅极&#xff0c;如 图 8 所示。 直接栅极驱动最艰巨的任务…

5‘-二磷酸鸟嘌呤核苷-岩藻糖二钠盐,GDP-Fucose,15839-70-0

中文名 5-二磷酸鸟嘌呤核苷-岩藻糖二钠盐 英文名 Guanosine 5′-diphospho-β-L-fucose sodium salt 英文别名 [(2R,3S,4R,5R)-5-(2-Amino-6-oxo-1,6-dihydro-9H-purin-9-yl)-3,4-dihydroxytetrahydro-2-furanyl]methyl (3S,4R,5S,6S)-3,4,5-trihydroxy-6-methyltetrahydro-2…