当前位置: 首页 > news >正文

【python爬虫】酷狗音乐爬取练习

注意:本次爬取的音乐仅有1分钟试听,仅作学习爬虫的原理,完整音乐需要自行下载客户端。

一、 初步分析

登陆酷狗音乐后随机选取一首歌,在请求里发现一段mp3文件,复制网址,确实是我们需要的url。

复制音频的名字,搜索找到发起请求的网址,发现是在songinfo里

查看参数和请求头,刷新一次,查看是否有哪些参数是变化的。可以发现图中两次请求的这些参数都不同,接下来就寻找这些参数的生成方式,参数clienttime为时间戳,那么就只需要找到signature的生成方式就可以了:

二、分析参数signature

1. 分析过程

搜索参数signature,并在可能生成的位置打上断点,然后刷新网页

网页断在了此处,可以看见参数signature跟函数d与数组s有关。

补充:如果s的长度不为13,需要放行一下,点击这个按钮

查看函数d的定义

发现函数内部没有wordsToBytes函数和函数i的相关定义,那么打下断点,查看具体函数的位置

获得wordsToBytes函数的具体定义

获得i函数的具体定义

i函数里没有r.stringToBytes(t)的相关定义,继续打下断点

找到r.stringToBytes(t)的相关定义

接着查看s的内容:在console里查看s的内容,发现s的值跟之前请求的参数类似。而且下标为0和下标为12的值跟u的值相同

往上查找u的定义,发现u的值是固定的

2. 代码实现

那么就开始实现生成signature的代码(以下为JavaScript代码

function bytesToWords(t) {for (var n = [], r = 0, e = 0; r < t.length; r++,e += 8)n[e >>> 5] |= t[r] << 24 - e % 32;return n
}function rotl(t, n) {return t << n | t >>> 32 - n
}function endian(t) {if (t.constructor == Number)return 16711935 & rotl(t, 8) | 4278255360 & rotl(t, 24);for (var n = 0; n < t.length; n++)t[n] = endian(t[n]);return t
}function i(t, c) {var l = {utf8: {stringToBytes: function (t) {return l.bin.stringToBytes(unescape(encodeURIComponent(t)))},bytesToString: function (t) {return decodeURIComponent(escape(l.bin.bytesToString(t)))}},bin: {stringToBytes: function (t) {for (var n = [], r = 0; r < t.length; r++)n.push(255 & t.charCodeAt(r));return n},bytesToString: function (t) {for (var n = [], r = 0; r < t.length; r++)n.push(String.fromCharCode(t[r]));return n.join("")}}};i._ff = function (t, n, r, e, o, i, c) {var s = t + (n & r | ~n & e) + (o >>> 0) + c;return (s << i | s >>> 32 - i) + n},i._gg = function (t, n, r, e, o, i, c) {var s = t + (n & e | r & ~e) + (o >>> 0) + c;return (s << i | s >>> 32 - i) + n},i._hh = function (t, n, r, e, o, i, c) {var s = t + (n ^ r ^ e) + (o >>> 0) + c;return (s << i | s >>> 32 - i) + n},i._ii = function (t, n, r, e, o, i, c) {var s = t + (r ^ (n | ~e)) + (o >>> 0) + c;return (s << i | s >>> 32 - i) + n};t.constructor == String ? t = c && "binary" === c.encoding ? o.stringToBytes(t) : l.utf8.stringToBytes(t) : e(t) ? t = Array.prototype.slice.call(t, 0) : Array.isArray(t) || (t = t.toString());for (var s = bytesToWords(t), a = 8 * t.length, l = 1732584193, u = -271733879, f = -1732584194, d = 271733878, g = 0; g < s.length; g++)s[g] = 16711935 & (s[g] << 8 | s[g] >>> 24) | 4278255360 & (s[g] << 24 | s[g] >>> 8);s[a >>> 5] |= 128 << a % 32,s[14 + (a + 64 >>> 9 << 4)] = a;for (var b = i._ff, p = i._gg, h = i._hh, m = i._ii, g = 0; g < s.length; g += 16) {var y = l, j = u, S = f, v = d;u = m(u = m(u = m(u = m(u = h(u = h(u = h(u = h(u = p(u = p(u = p(u = p(u = b(u = b(u = b(u = b(u, f = b(f, d = b(d, l = b(l, u, f, d, s[g + 0], 7, -680876936), u, f, s[g + 1], 12, -389564586), l, u, s[g + 2], 17, 606105819), d, l, s[g + 3], 22, -1044525330), f = b(f, d = b(d, l = b(l, u, f, d, s[g + 4], 7, -176418897), u, f, s[g + 5], 12, 1200080426), l, u, s[g + 6], 17, -1473231341), d, l, s[g + 7], 22, -45705983), f = b(f, d = b(d, l = b(l, u, f, d, s[g + 8], 7, 1770035416), u, f, s[g + 9], 12, -1958414417), l, u, s[g + 10], 17, -42063), d, l, s[g + 11], 22, -1990404162), f = b(f, d = b(d, l = b(l, u, f, d, s[g + 12], 7, 1804603682), u, f, s[g + 13], 12, -40341101), l, u, s[g + 14], 17, -1502002290), d, l, s[g + 15], 22, 1236535329), f = p(f, d = p(d, l = p(l, u, f, d, s[g + 1], 5, -165796510), u, f, s[g + 6], 9, -1069501632), l, u, s[g + 11], 14, 643717713), d, l, s[g + 0], 20, -373897302), f = p(f, d = p(d, l = p(l, u, f, d, s[g + 5], 5, -701558691), u, f, s[g + 10], 9, 38016083), l, u, s[g + 15], 14, -660478335), d, l, s[g + 4], 20, -405537848), f = p(f, d = p(d, l = p(l, u, f, d, s[g + 9], 5, 568446438), u, f, s[g + 14], 9, -1019803690), l, u, s[g + 3], 14, -187363961), d, l, s[g + 8], 20, 1163531501), f = p(f, d = p(d, l = p(l, u, f, d, s[g + 13], 5, -1444681467), u, f, s[g + 2], 9, -51403784), l, u, s[g + 7], 14, 1735328473), d, l, s[g + 12], 20, -1926607734), f = h(f, d = h(d, l = h(l, u, f, d, s[g + 5], 4, -378558), u, f, s[g + 8], 11, -2022574463), l, u, s[g + 11], 16, 1839030562), d, l, s[g + 14], 23, -35309556), f = h(f, d = h(d, l = h(l, u, f, d, s[g + 1], 4, -1530992060), u, f, s[g + 4], 11, 1272893353), l, u, s[g + 7], 16, -155497632), d, l, s[g + 10], 23, -1094730640), f = h(f, d = h(d, l = h(l, u, f, d, s[g + 13], 4, 681279174), u, f, s[g + 0], 11, -358537222), l, u, s[g + 3], 16, -722521979), d, l, s[g + 6], 23, 76029189), f = h(f, d = h(d, l = h(l, u, f, d, s[g + 9], 4, -640364487), u, f, s[g + 12], 11, -421815835), l, u, s[g + 15], 16, 530742520), d, l, s[g + 2], 23, -995338651), f = m(f, d = m(d, l = m(l, u, f, d, s[g + 0], 6, -198630844), u, f, s[g + 7], 10, 1126891415), l, u, s[g + 14], 15, -1416354905), d, l, s[g + 5], 21, -57434055), f = m(f, d = m(d, l = m(l, u, f, d, s[g + 12], 6, 1700485571), u, f, s[g + 3], 10, -1894986606), l, u, s[g + 10], 15, -1051523), d, l, s[g + 1], 21, -2054922799), f = m(f, d = m(d, l = m(l, u, f, d, s[g + 8], 6, 1873313359), u, f, s[g + 15], 10, -30611744), l, u, s[g + 6], 15, -1560198380), d, l, s[g + 13], 21, 1309151649), f = m(f, d = m(d, l = m(l, u, f, d, s[g + 4], 6, -145523070), u, f, s[g + 11], 10, -1120210379), l, u, s[g + 2], 15, 718787259), d, l, s[g + 9], 21, -343485551),l = l + y >>> 0,u = u + j >>> 0,f = f + S >>> 0,d = d + v >>> 0}return endian([l, u, f, d])
}function wordsToBytes(t) {for (var n = [], r = 0; r < 32 * t.length; r += 8)n.push(t[r >>> 5] >>> 24 - r % 32 & 255);return n
}function bytesToHex(t) {for (var n = [], r = 0; r < t.length; r++)n.push((t[r] >>> 4).toString(16)),n.push((15 & t[r]).toString(16));return n.join("")
}function d(t, r) {if (void 0 === t || null === t)throw new Error("Illegal argument " + t);var e = wordsToBytes(i(t, r));return r && r.asBytes ? e : r && r.asString ? o.bytesToString(e) : bytesToHex(e)
}function getsianature() {var s = ["NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt","appid=1014","clienttime=1741411989613","clientver=20000","dfid=3Mm61k0WDxvm033Epz2worRG","encode_album_audio_id=j410q60","mid=70789bebe63fb74c52e4a911853f5450","platid=4","srcappid=2919","token=cbfe2e174e4b97fd6aca35682cdba3d2b431c4ed95e2dbd1779e37a7975b672c","userid=2307902397","uuid=70789bebe63fb74c52e4a911853f5450","NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt"];return d(s.join(""))
}console.log(getsianature());

经过一系列调试,可以发现生成的结果与浏览器生成的值一样,那么生成signature的代码就没问题了。

将一些会变的值改为变量,可以看到参数s的值里只有clienttime的值是会变的,因此修改上述代码中getsianature函数,将参数s的值放在python代码中,getsianature函数改完如下图所示:

function getsianature(s) {return d(s.join(""))
}

三、获取多首歌

1. 分析过程

点击不同的歌,可以发现每首歌的参数encode_album_audio_id都不同,因此需要获取encode_album_audio_id

搜索歌名,找到歌曲的id

接着查看请求参数,同样有一个signature参数,刷新多次网页发现signature参数会变化,那么重复之前分析signature的步骤

打下断点,查看中断的位置,参数s有所变化

打印s,查看s的内容,除此之外没有变化,那么就沿用先前的代码

2. 代码实现

完整代码如下,注意这里调用了JavaScript代码,需要安装PyExecJS模块:pip install PyExecJS -i https://pypi.tuna.tsinghua.edu.cn/simple。

本代码中JavaScript文件名为kugou.js,JavaScript代码在参数signature的分析中有写到,以下为python代码:

import json
import re
import time
import requests
import execjsclass kugou_music:def __init__(self):self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36','Referer': 'https://www.kugou.com/',}def get_signature(self, s):with open("kugou.js", "r", encoding="utf-8") as f:js = f.read()ctx = execjs.compile(js)signature = ctx.call("getsianature", s)return signaturedef get_one_song_url(self, audio_id):timestamp = str(int(time.time() * 1000))s = ["NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt","appid=1014",f"clienttime={timestamp}","clientver=20000","dfid=3Mm61k0WDxvm033Epz2worRG",f"encode_album_audio_id={audio_id}","mid=70789bebe63fb74c52e4a911853f5450","platid=4","srcappid=2919","token=cbfe2e174e4b97fd6aca35682cdba3d2b431c4ed95e2dbd1779e37a7975b672c","userid=2307902397","uuid=70789bebe63fb74c52e4a911853f5450","NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt"]signature = self.get_signature(s)params = {'srcappid': '2919','clientver': '20000','clienttime': timestamp,'mid': '70789bebe63fb74c52e4a911853f5450','uuid': '70789bebe63fb74c52e4a911853f5450','dfid': '3Mm61k0WDxvm033Epz2worRG','appid': '1014','platid': '4','encode_album_audio_id': audio_id,'token': 'cbfe2e174e4b97fd6aca35682cdba3d2b431c4ed95e2dbd1779e37a7975b672c','userid': '2307902397','signature': signature}one_song_url = 'https://wwwapi.kugou.com/play/songinfo'response = requests.get(one_song_url, headers=self.headers, params=params)song_url = response.json()['data']['play_url']return song_urldef get_signal_music(self, audio_id, audio_name):song_url = self.get_one_song_url(audio_id)response = requests.get(song_url, headers=self.headers)with open(f'{audio_name}.mp3', 'wb') as f:f.write(response.content)print(f'{audio_name}.mp3下载完成')def get_song_id(self,keyword):timestamp = str(int(time.time() * 1000))s = ["NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt","appid=1014","bitrate=0","callback=callback123",f"clienttime={timestamp}","clientver=1000","dfid=3Mm61k0WDxvm033Epz2worRG","filter=10","inputtype=0","iscorrection=1","isfuzzy=0",f"keyword={keyword}","mid=70789bebe63fb74c52e4a911853f5450","page=1","pagesize=30","platform=WebFilter","privilege_filter=0","srcappid=2919","token=cbfe2e174e4b97fd6aca35682cdba3d2b431c4ed95e2dbd1779e37a7975b672c","userid=2307902397","uuid=70789bebe63fb74c52e4a911853f5450","NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt"]signature = self.get_signature(s)params = {'callback': 'callback123','srcappid': '2919','clientver': '1000','clienttime': timestamp,'mid': '70789bebe63fb74c52e4a911853f5450','uuid': '70789bebe63fb74c52e4a911853f5450','dfid': '3Mm61k0WDxvm033Epz2worRG','keyword': keyword,'page': '1','pagesize': '30','bitrate': '0','isfuzzy': '0','inputtype': '0','platform': 'WebFilter','userid': '2307902397','iscorrection': '1','privilege_filter': '0','filter': '10','token': 'cbfe2e174e4b97fd6aca35682cdba3d2b431c4ed95e2dbd1779e37a7975b672c','appid': '1014','signature': signature}song_id_url = 'https://complexsearchretry.kugou.com/v2/search/song'response = requests.get(song_id_url, headers=self.headers, params=params, verify=False)temp = re.findall(r'callback123(.*)', response.text)[0][1:-1]temp = json.loads(temp)song = temp['data']['lists']return songdef get_all_song(self,keyword):song = self.get_song_id(keyword)for i in song:song_id = i.get('EMixSongID')song_name = i.get('FileName')# print(song_name, song_id)try:self.get_signal_music(song_id, song_name)except Exception as e:print(f'{song_name}下载失败:', e)if __name__ == '__main__':kugou = kugou_music()# kugou.get_signal_music('j410q60')keyword='周杰伦'kugou.get_all_song(keyword)

相关文章:

【python爬虫】酷狗音乐爬取练习

注意&#xff1a;本次爬取的音乐仅有1分钟试听&#xff0c;仅作学习爬虫的原理&#xff0c;完整音乐需要自行下载客户端。 一、 初步分析 登陆酷狗音乐后随机选取一首歌&#xff0c;在请求里发现一段mp3文件&#xff0c;复制网址&#xff0c;确实是我们需要的url。 复制音频的…...

阿里云 DataWorks面试题集锦及参考答案

目录 简述阿里云 DataWorks 的核心功能模块及其在企业数据治理中的作用 简述 DataWorks 的核心功能模块及其应用场景 解释 DataWorks 中工作空间、项目、业务流程的三层逻辑关系 解释 DataWorks 中的 “节点”、“工作流” 和 “依赖关系” 设计 解释 DataWorks 中 “周期任…...

uniapp+Vue3 开发小程序的下载文件功能

小程序下载文件&#xff0c;可以先预览文件内容&#xff0c;然后在手机上打开文件的工具中选择保存。 简单示例&#xff1a;&#xff08;复制到HBuilder直接食用即可&#xff09; <template><view class"container-detail"><view class"example…...

Apache Log4j 2

目录 1. Apache Log4j 2 简介 1.1 什么是Log4j 2&#xff1f; 1.2 Log4j 2 的主要特性 2. Log4j 2 的核心组件 2.1 Logger 2.2 Appender 2.3 Layout 2.4 Filter 2.5 Configuration 3. Log4j 2 的配置 4. Log4j 2 的使用示例 4.1 Maven 依赖 4.2 示例代码 4.3 输出…...

4.2.2 ArrayList类

ArrayList类与List类的用法差不多&#xff0c;提供的方法也差不多。但是与List不同的是&#xff0c;ArrayList可以包含任意类型的数据&#xff0c;但是相应的&#xff0c;要使用包含的数据&#xff0c;就必须对数据做相应的装箱和拆箱&#xff08;关于装箱和拆箱&#xff0c;请…...

L1-088 静静的推荐

L1-088 静静的推荐 - 团体程序设计天梯赛-练习集 (pintia.cn) 题解 这里代码很简单&#xff0c;但是主要是循环里面的内容很难理解&#xff0c;下面是关于循环里面的内容理解&#xff1a; 这里 n 10 表示有 10 个学生&#xff0c;k 2 表示企业接受 2 批次的推荐名单&#…...

普及听力保健知识竞赛

普及听力保健知识竞赛 热点指数&#xff1a;★★★ 日期&#xff1a;3月3日 关键词&#xff1a;爱耳护耳、听力健康、耳部保健、听力科普 适合行业&#xff1a;医疗健康、健康护理、教育培训、公益组织 推荐功能&#xff1a;答题、H5宣传 宣传方向&#xff1a;广泛普及听力…...

小结: IGMP协议

IGMP&#xff08;Internet Group Management Protocol&#xff09;协议详解 IGMP&#xff08;Internet Group Management Protocol&#xff09;是IPv4 组播&#xff08;Multicast&#xff09;通信的控制协议&#xff0c;主要用于主机和路由器之间的组播成员管理。IGMP 允许主机…...

Dify 本地部署教程

目录 一、下载安装包 二、修改配置 三、启动容器 四、访问 Dify 五、总结 本篇文章主要记录 Dify 本地部署过程,有问题欢迎交流~ 一、下载安装包 从 Github 仓库下载最新稳定版软件包,点击下载~,当然也可以克隆仓库或者从仓库里直接下载zip源码包。 目前最新版本是V…...

ConcurrentHashMap从源码总结使用注意事项(源码)

ConcurrentHashMap实现原理 目录 ConcurrentHashMap实现原理核心源码解读&#xff08;1&#xff09;数据结构: 采用数组链表/红黑树&#xff08;2&#xff09;初始化&#xff08;3&#xff09;并发扩容&#xff08;4&#xff09;put 操作流程&#xff08;5&#xff09;计数 siz…...

前端 UI 框架发展史

上一小节我们了解了前端 UI 框架的作用和意义&#xff0c;接下来我们再来了解前端 UI 框架的发展历史。 虽然是讲历史&#xff0c;但我不想讲得太复杂&#xff0c;也不打算搞什么编年史记录啥的&#xff0c;毕竟我们不是来学历史的。 我会简单描述一下前端 UI 框架的发展历程…...

【工控】线扫相机小结 第五篇

背景介绍 线扫相机通过光栅尺的脉冲触发&#xff0c; 我在调试线扫过程中&#xff0c;发现图像被拉伸&#xff0c;预设调节分配器。图像正常后&#xff0c;我提高的相机的扫描速度&#xff08;Y轴动的更快了&#xff09;。 动的更快的发现&#xff0c;图像变短了&#xff08;以…...

AI与SEO关键词智能解析

内容概要 人工智能技术正重塑搜索引擎优化的底层逻辑&#xff0c;其核心突破体现在关键词解析维度的结构性升级。通过机器学习算法对海量搜索数据的动态学习&#xff0c;AI不仅能够识别传统TF-IDF模型中的高频词汇&#xff0c;更能捕捉语义网络中隐含的关联特征。下表展示了传…...

STM32---FreeRTOS消息队列

一、简介 1、队列简介&#xff1a; 队列&#xff1a;是任务到任务&#xff0c;任务到中断、中断到任务数据交流的一种机制&#xff08;消息传递&#xff09;。 FreeRTOS基于队列&#xff0c;实现了多种功能&#xff0c;其中包括队列集、互斥信号量、计数型信号量、二值信号量…...

开关模式电源转换器 EMI/EMC 的集成仿真

介绍 在电力电子领域&#xff0c;电磁干扰 &#xff08;EMI&#xff09; 和电磁兼容性 &#xff08;EMC&#xff09; 问题可以决定设计的成败。开关模式电源转换器虽然高效且紧凑&#xff0c;但却是电磁噪声的常见来源&#xff0c;可能会对附近的组件和系统造成严重破坏。随着…...

Java虚拟机之垃圾收集(一)

目录 一、如何判定对象“生死”&#xff1f; 1. 引用计数算法&#xff08;理论参考&#xff09; 2. 可达性分析算法&#xff08;JVM 实际使用&#xff09; 3. 对象的“缓刑”机制 二、引用类型与回收策略 三、何时触发垃圾回收&#xff1f; 1. 分代回收策略 2. 手动触发…...

linux---天气爬虫

代码概述 这段代码实现了一个天气查询系统&#xff0c;支持实时天气、未来天气和历史天气查询。用户可以通过终端菜单选择查询类型&#xff0c;并输入城市名称来获取相应的天气信息。程序通过 TCP 连接发送 HTTP 请求&#xff0c;并解析返回的 JSON 数据来展示天气信息。 #in…...

字节顺序(大小端序)

在弄明白字节顺序之前先了解一下一些基础概念. 基础概念 字节&#xff08;byte&#xff09;‌&#xff1a; 字节是计算机中数据处理的基本单位&#xff0c;通常由8个位组成&#xff0c;即1字节等于8位。一个字节可以存储一个ASCII码&#xff0c;两个字节可以存放一个汉字国标…...

可复用的 Vue 轮播图组件

大家好&#xff0c;今天我想和大家分享一下如何开发一个通用的 Vue 轮播图组件。轮播图在各种网站中都很常见&#xff0c;无论是展示产品、活动还是文章&#xff0c;都能派上用场。我们今天要实现的这个组件会具备良好的可配置性和易用性&#xff0c;同时保证代码的可维护性。 …...

AI编程: 一个案例对比CPU和GPU在深度学习方面的性能差异

背景 字节跳动正式发布中国首个AI原生集成开发环境工具&#xff08;AI IDE&#xff09;——AI编程工具Trae国内版。 该工具模型搭载doubao-1.5-pro&#xff0c;支持切换满血版DeepSeek R1&V3&#xff0c; 可以帮助各阶段开发者与AI流畅协作&#xff0c;更快、更高质量地完…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险

C#入门系列【类的基本概念】&#xff1a;开启编程世界的奇妙冒险 嘿&#xff0c;各位编程小白探险家&#xff01;欢迎来到 C# 的奇幻大陆&#xff01;今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类&#xff01;别害怕&#xff0c;跟着我&#xff0c;保准让你轻松搞…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化

是不是受够了安装了oracle database之后sqlplus的简陋&#xff0c;无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话&#xff0c;配置.bahs_profile后也能解决上下翻页这些&#xff0c;但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可&#xff0c…...