js逆向实战(1)-- 某☁️音乐下载
下载某云音乐源文件.mp4格式

首先随便点进一首歌,如图所示获取该音乐id,然后点击播放键,打开F12进行查询XHR



由此可知,实际请求网址是
https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token=「你的token」url需带上token,请求参数有两个:params、encSecKey返回json里的id就是该音乐id,url就是本次的目标音乐源文件链接
继续查看启动器,查看该路由的调用堆栈信息,找到关键位置打断点,不会找断点的就每个堆栈全部点进去设置断点,然后看哪一个断点结束后url已完成请求的就是关键位置,从下图的文件中可知,核心文件是core_xxxxx.js,可以直接下载到本地方便查看代码。(堆栈执行顺序是由下至上)


第一步,已成功定位到请求路由,e7d.data里已经带有(params、encSecKey),后续就直接会请求了,那么就继续向上一个堆栈找此函数的参数(x7q,e7d)中的e7d是从哪里传的。
PS:请注意,一定要找到我们要找的核心url是否由此断点发出的,由于一些方法会被反复调用,参数值是不一定的。
第二步,上图已封装好了e7d,且参数params、encSecKey已出现,是由window.asrsea产生的,继续查找window.asrsea是哪个方法。
window.asrsea(JSON.stringify(i7b), bsc2x(["流泪", "强"]), bsc2x(RU7N.md), bsc2x(["爱心", "女孩", "惊恐", "大笑"]));
鼠标悬浮该方法后定位至这里,核心就是这个function d,接受4个参数,分别对应上面的4个值。
其中第一个参数i7b是以下参数构成music_id = XXXXXX
song_data = {"ids": f"[{music_id}]","level": "standard","encodeType": "aac","csrf_token": csrf_token
}第三个参数md是一个固定列表,第二、第四个参数也是一个短列表值。


核心方法已找到,就是function d(),剩下的工作就是把d方法里需要涉及到的所有function全部找出来,比如function b、c,然后继续从b、c里继续递归找方法,这一步工作比较繁琐需要耐心。直至自己用js能把function d给跑通就算成功。
通过js里的方法可知,里面算法还涉及到了加密,需要用到crypto-js库,上网百度搜一下直接下载该库的代码保存本地。

以下是js文件代码:
var CryptoJS = require('./package/crypto-js.js');var bd7W = {};var maxDigits,ZERO_ARRAY,bigZero,bigOne,dpl10,lr10,hexatrigesimalToChar,hexToChar,highBitMasks,lowBitMasks,biRadixBase = 2,biRadixBits = 16,bitsPerDigit = biRadixBits,biRadix = 65536,biHalfRadix = biRadix >>> 1,biRadixSquared = biRadix * biRadix,maxDigitVal = biRadix - 1,maxInteger = 9999999999999998;setMaxDigits(20),dpl10 = 15,lr10 = biFromNumber(1e15),hexatrigesimalToChar = new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"),hexToChar = new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"),highBitMasks = new Array(0, 32768, 49152, 57344, 61440, 63488, 64512, 65024, 65280, 65408, 65472, 65504, 65520, 65528, 65532, 65534, 65535),lowBitMasks = new Array(0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535);function encryptedString(a, b) {for (var f, g, h, i, j, k, l, c = new Array, d = b.length, e = 0; d > e;)c[e] = b.charCodeAt(e),e++;for (; 0 != c.length % a.chunkSize;)c[e++] = 0;for (f = c.length, g = "", e = 0; f > e; e += a.chunkSize) {for (j = new BigInt, h = 0, i = e; i < e + a.chunkSize; ++h)j.digits[h] = c[i++],j.digits[h] += c[i++] << 8;k = a.barrett.powMod(j, a.e),l = 16 == a.radix ? biToHex(k) : biToString(k, a.radix),g += l + " "}return g.substring(0, g.length - 1)
}function biSubtract(a, b) {var c,d,e,f;if (a.isNeg != b.isNeg)b.isNeg = !b.isNeg,c = biAdd(a, b),b.isNeg = !b.isNeg;else {for (c = new BigInt, e = 0, f = 0; f < a.digits.length; ++f)d = a.digits[f] - b.digits[f] + e,c.digits[f] = 65535 & d,c.digits[f] < 0 && (c.digits[f] += biRadix),e = 0 - Number(0 > d);if (-1 == e) {for (e = 0, f = 0; f < a.digits.length; ++f)d = 0 - c.digits[f] + e,c.digits[f] = 65535 & d,c.digits[f] < 0 && (c.digits[f] += biRadix),e = 0 - Number(0 > d);c.isNeg = !a.isNeg} elsec.isNeg = a.isNeg}return c
}function biCompare(a, b) {if (a.isNeg != b.isNeg)return 1 - 2 * Number(a.isNeg);for (var c = a.digits.length - 1; c >= 0; --c)if (a.digits[c] != b.digits[c])return a.isNeg ? 1 - 2 * Number(a.digits[c] > b.digits[c]) : 1 - 2 * Number(a.digits[c] < b.digits[c]);return 0}function biMultiplyByRadixPower(a, b) {var c = new BigInt;return arrayCopy(a.digits, 0, c.digits, b, c.digits.length - b), c}function arrayCopy(a, b, c, d, e) {var g,h,f = Math.min(b + e, a.length);for (g = b, h = d; f > g; ++g, ++h)c[h] = a[g]}function biShiftLeft(a, b) {var e,f,g,h,c = Math.floor(b / bitsPerDigit),d = new BigInt;for (arrayCopy(a.digits, 0, d.digits, c, d.digits.length - c), e = b % bitsPerDigit, f = bitsPerDigit - e, g = d.digits.length - 1, h = g - 1; g > 0; --g, --h)d.digits[g] = d.digits[g] << e & maxDigitVal | (d.digits[h] & highBitMasks[e]) >>> f;return d.digits[0] = d.digits[g] << e & maxDigitVal, d.isNeg = a.isNeg, d}function biFromNumber(a) {var c,b = new BigInt;for (b.isNeg = 0 > a, a = Math.abs(a), c = 0; a > 0;)b.digits[c++] = a & maxDigitVal,a >>= biRadixBits;return b}function biNumBits(a) {var e,b = biHighIndex(a),c = a.digits[b],d = (b + 1) * bitsPerDigit;for (e = d; e > d - bitsPerDigit && 0 == (32768 & c); --e)c <<= 1;return e}function biDivideModulo(a, b) {var f,g,h,i,j,k,l,m,n,o,p,q,r,s,c = biNumBits(a),d = biNumBits(b),e = b.isNeg;if (d > c)return a.isNeg ? (f = biCopy(bigOne), f.isNeg = !b.isNeg, a.isNeg = !1, b.isNeg = !1, g = biSubtract(b, a), a.isNeg = !0, b.isNeg = e) : (f = new BigInt, g = biCopy(a)), new Array(f, g);for (f = new BigInt, g = a, h = Math.ceil(d / bitsPerDigit) - 1, i = 0; b.digits[h] < biHalfRadix;)b = biShiftLeft(b, 1),++i,++d,h = Math.ceil(d / bitsPerDigit) - 1;for (g = biShiftLeft(g, i), c += i, j = Math.ceil(c / bitsPerDigit) - 1, k = biMultiplyByRadixPower(b, j - h); -1 != biCompare(g, k);)++f.digits[j - h],g = biSubtract(g, k);for (l = j; l > h; --l) {for (m = l >= g.digits.length ? 0 : g.digits[l], n = l - 1 >= g.digits.length ? 0 : g.digits[l - 1], o = l - 2 >= g.digits.length ? 0 : g.digits[l - 2], p = h >= b.digits.length ? 0 : b.digits[h], q = h - 1 >= b.digits.length ? 0 : b.digits[h - 1], f.digits[l - h - 1] = m == p ? maxDigitVal : Math.floor((m * biRadix + n) / p), r = f.digits[l - h - 1] * (p * biRadix + q), s = m * biRadixSquared + (n * biRadix + o); r > s;)--f.digits[l - h - 1],r = f.digits[l - h - 1] * (p * biRadix | q),s = m * biRadix * biRadix + (n * biRadix + o);k = biMultiplyByRadixPower(b, l - h - 1),g = biSubtract(g, biMultiplyDigit(k, f.digits[l - h - 1])),g.isNeg && (g = biAdd(g, k), --f.digits[l - h - 1])}return g = biShiftRight(g, i), f.isNeg = a.isNeg != e, a.isNeg && (f = e ? biAdd(f, bigOne) : biSubtract(f, bigOne), b = biShiftRight(b, i), g = biSubtract(b, g)), 0 == g.digits[0] && 0 == biHighIndex(g) && (g.isNeg = !1), new Array(f, g)}function BarrettMu_modulo(a) {var i,b = biDivideByRadixPower(a, this.k - 1),c = biMultiply(b, this.mu),d = biDivideByRadixPower(c, this.k + 1),e = biModuloByRadixPower(a, this.k + 1),f = biMultiply(d, this.modulus),g = biModuloByRadixPower(f, this.k + 1),h = biSubtract(e, g);for (h.isNeg && (h = biAdd(h, this.bkplus1)), i = biCompare(h, this.modulus) >= 0; i;)h = biSubtract(h, this.modulus),i = biCompare(h, this.modulus) >= 0;return h}function BarrettMu_multiplyMod(a, b) {var c = biMultiply(a, b);return this.modulo(c)}function biDivideByRadixPower(a, b) {var c = new BigInt;return arrayCopy(a.digits, b, c.digits, 0, c.digits.length - b), c}function reverseStr(a) {var c,b = "";for (c = a.length - 1; c > -1; --c)b += a.charAt(c);return b}function digitToHex(a) {var b = 15,c = "";for (i = 0; 4 > i; ++i)c += hexToChar[a & b],a >>>= 4;return reverseStr(c)}function biToHex(a) {var d,b = "";for (biHighIndex(a), d = biHighIndex(a); d > -1; --d)b += digitToHex(a.digits[d]);return b}function biModuloByRadixPower(a, b) {var c = new BigInt;return arrayCopy(a.digits, 0, c.digits, 0, b), c}function biCompare(a, b) {if (a.isNeg != b.isNeg)return 1 - 2 * Number(a.isNeg);for (var c = a.digits.length - 1; c >= 0; --c)if (a.digits[c] != b.digits[c])return a.isNeg ? 1 - 2 * Number(a.digits[c] > b.digits[c]) : 1 - 2 * Number(a.digits[c] < b.digits[c]);return 0}function biMultiply(a, b) {var d,h,i,k,c = new BigInt,e = biHighIndex(a),f = biHighIndex(b);for (k = 0; f >= k; ++k) {for (d = 0, i = k, j = 0; e >= j; ++j, ++i)h = c.digits[i] + a.digits[j] * b.digits[k] + d,c.digits[i] = h & maxDigitVal,d = h >>> biRadixBits;c.digits[k + e + 1] = d}return c.isNeg = a.isNeg != b.isNeg, c}function BarrettMu_powMod(a, b) {var d,e,c = new BigInt;for (c.digits[0] = 1, d = a, e = b;;) {if (0 != (1 & e.digits[0]) && (c = this.multiplyMod(c, d)), e = biShiftRight(e, 1), 0 == e.digits[0] && 0 == biHighIndex(e))break;d = this.multiplyMod(d, d)}return c}function biShiftRight(a, b) {var e,f,g,h,c = Math.floor(b / bitsPerDigit),d = new BigInt;for (arrayCopy(a.digits, c, d.digits, 0, a.digits.length - c), e = b % bitsPerDigit, f = bitsPerDigit - e, g = 0, h = g + 1; g < d.digits.length - 1; ++g, ++h)d.digits[g] = d.digits[g] >>> e | (d.digits[h] & lowBitMasks[e]) << f;return d.digits[d.digits.length - 1] >>>= e, d.isNeg = a.isNeg, d}function biMultiplyDigit(a, b) {var c,d,e,f;for (result = new BigInt, c = biHighIndex(a), d = 0, f = 0; c >= f; ++f)e = result.digits[f] + a.digits[f] * b + d,result.digits[f] = e & maxDigitVal,d = e >>> biRadixBits;return result.digits[1 + c] = d, result}function biDivide(a, b) {return biDivideModulo(a, b)[0]}function biCopy(a) {var b = new BigInt(!0);return b.digits = a.digits.slice(0), b.isNeg = a.isNeg, b}function BarrettMu(a) {this.modulus = biCopy(a),this.k = biHighIndex(this.modulus) + 1;var b = new BigInt;b.digits[2 * this.k] = 1,this.mu = biDivide(b, this.modulus),this.bkplus1 = new BigInt,this.bkplus1.digits[this.k + 1] = 1,this.modulo = BarrettMu_modulo,this.multiplyMod = BarrettMu_multiplyMod,this.powMod = BarrettMu_powMod}function BigInt(a) {this.digits = "boolean" == typeof a && 1 == a ? null : ZERO_ARRAY.slice(0),this.isNeg = !1}function charToHex(a) {var h,b = 48,c = b + 9,d = 97,e = d + 25,f = 65,g = 90;return h = a >= b && c >= a ? a - b : a >= f && g >= a ? 10 + a - f : a >= d && e >= a ? 10 + a - d : 0}function hexToDigit(a) {var d,b = 0,c = Math.min(a.length, 4);for (d = 0; c > d; ++d)b <<= 4,b |= charToHex(a.charCodeAt(d));return b
}function biFromHex(a) {var d,e,b = new BigInt,c = a.length;for (d = c, e = 0; d > 0; d -= 4, ++e)b.digits[e] = hexToDigit(a.substr(Math.max(d - 4, 0), Math.min(d, 4)));return b}function RSAKeyPair(a, b, c) {this.e = biFromHex(a),this.d = biFromHex(b),this.m = biFromHex(c),this.chunkSize = 2 * biHighIndex(this.m),this.radix = 16,this.barrett = new BarrettMu(this.m)}function biHighIndex(a) {for (var b = a.digits.length - 1; b > 0 && 0 == a.digits[b];)--b;return b}function setMaxDigits(a) {maxDigits = a,ZERO_ARRAY = new Array(maxDigits);for (var b = 0; b < ZERO_ARRAY.length; b++)ZERO_ARRAY[b] = 0;bigZero = new BigInt,bigOne = new BigInt,bigOne.digits[0] = 1}var Hb6V = function(i7b, u7n) {try {u7n = u7n.toLowerCase();if (i7b === null)return u7n == "null";if (i7b === undefined)return u7n == "undefined";return bd7W.toString.call(i7b).toLowerCase() == "[object " + u7n + "]"} catch (e) {console.log(e)return !1}};var md = ["色", "流感", "这边", "弱", "嘴唇", "亲", "开心", "呲牙", "憨笑", "猫", "皱眉", "幽灵", "蛋糕", "发怒", "大哭", "兔子", "星星", "钟情", "牵手", "公鸡", "爱意", "禁止", "狗", "亲亲", "叉", "礼物", "晕", "呆", "生病", "钻石", "拜", "怒", "示爱", "汗", "小鸡", "痛苦", "撇嘴", "惶恐", "口罩", "吐舌", "心碎", "生气", "可爱", "鬼脸", "跳舞", "男孩", "奸笑", "猪", "圈", "便便", "外星", "圣诞"]var emj = {"色": "00e0b","流感": "509f6","这边": "259df","弱": "8642d","嘴唇": "bc356","亲": "62901","开心": "477df","呲牙": "22677","憨笑": "ec152","猫": "b5ff6","皱眉": "8ace6","幽灵": "15bb7","蛋糕": "b7251","发怒": "52b3a","大哭": "b17a8","兔子": "76aea","星星": "8a5aa","钟情": "76d2e","牵手": "41762","公鸡": "9ec4e","爱意": "e341f","禁止": "56135","狗": "fccf6","亲亲": "95280","叉": "104e0","礼物": "312ec","晕": "bda92","呆": "557c9","生病": "38701","钻石": "14af6","拜": "c9d05","怒": "c4f7f","示爱": "0c368","汗": "5b7a4","小鸡": "6bee2","痛苦": "55932","撇嘴": "575cc","惶恐": "e10b4","口罩": "24d81","吐舌": "3cfe4","心碎": "875d3","生气": "e8204","可爱": "7b97d","鬼脸": "def52","跳舞": "741d5","男孩": "46b8e","奸笑": "289dc","猪": "6935b","圈": "3ece0","便便": "462db","外星": "0a22b","圣诞": "8e7","流泪": "01000","强": "1","爱心": "0CoJU","女孩": "m6Qyw","惊恐": "8W8ju","大笑": "d"}var gO9F = function(i7b) {return Hb6V(i7b, "function")}var bh7a = function(k7d, cH8z, O7H) {if (!k7d || !k7d.length || !gO9F(cH8z))return this;if (!!k7d.forEach) {k7d.forEach(cH8z, O7H);return this}for (var i = 0, l = k7d.length; i < l; i++)cH8z.call(O7H, k7d[i], i, k7d);return this}var bsc2x = function(cya8S) {var m7f = [];bh7a(cya8S, function(cxZ8R) {m7f.push(emj[cxZ8R])});return m7f.join("")};function a(a) {var d,e,b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",c = "";for (d = 0; a > d; d += 1)e = Math.random() * b.length,e = Math.floor(e),c += b.charAt(e);return c}function b(a, b) {var c = CryptoJS.enc.Utf8.parse(b),d = CryptoJS.enc.Utf8.parse("0102030405060708"),e = CryptoJS.enc.Utf8.parse(a),f = CryptoJS.AES.encrypt(e, c, {iv: d,mode: CryptoJS.mode.CBC});return f.toString()}function c(a, b, c) {var d,e;return setMaxDigits(131), d = new RSAKeyPair(b, "", c), e = encryptedString(d, a)}function decrypt(d, e, f, g) {var h = {}, i = a(16);return h.encText = b(d, g),h.encText = b(h.encText, i),h.encSecKey = c(i, e, f),h}function e(a, b, d, e) {var f = {};return f.encText = c(a + e, b, d), f}function get_efg(){var r = {}r.e = bsc2x(["流泪", "强"])r.f = bsc2x(md)r.g = bsc2x(["爱心", "女孩", "惊恐", "大笑"])return r}
以下是python部分代码,由于要用到js,需要用到execjs库,自行百度pip install。
import traceback
import json
import requests
import execjswith open("wangyiyun.js") as f:jscode = f.read()
js = execjs.compile(jscode)csrf_token = "your_token"
url = f"https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token={csrf_token}"headers = {"Accept": "*/*","Host": "music.163.com","Accept-Language": "zh-CN,zh-Hans;q=0.9","Content-Type": "application/x-www-form-urlencoded","Accept-Encoding": "gzip, deflate, br","User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.2 Safari/605.1.15","Referer": "https://music.163.com/","Connection": "keep-alive","Cookie": "ntes_kaola_ad=1; JSESSIONID-WYYY=NNam6ZvnitTQAIxhjcnkVGOJe1CSrnqIOsBnuOzx405%2FJAUSng5IDkYIFo00Xb%2BoUldg8unn3ikRohd8TEg%2F5A9IF0d3vIrPq0ggue%2BD%2FCFTwZBaj%2FfbHOgwt15v2R4uXH8%2FJuMri%2F3zPb%2Bl7TH%2B4XFVYq9BghtkAelO6p5uAC4QQxNh%3A1735613258319; _iuqxldmzr_=32; playerid=96541318; WEVNSM=1.0.0; WM_TID=%2FnYekZpayJFEEEVQRRfHMEPNaHmTqyHZ; MUSIC_U=006C5AF78BF74B16F27E5B57A85731911569EB8ABB9380E9315B54803127FFDF3C459640CCB0E2BDE8425D2EE33764BC1DB30AA186B850E1CED2B79EF2436E56F8786A63776BFC2243956C5AC987B3A85797BC545993FB84F14E3C4C66EF506A087542A5DE0B218EEA044FDCED41F7037A2EA93679113D60D72EAD7603A7B74BAF1EA4753BF65B585F5130F58CC7711D5EB79F559AD803761591C3D9AB83F967DDFA019B5C6C58BB126197139D1D4BB311DED63FECC8F6651349C211AEE6BB2A772FFCB717C731082DE27A19C5F24FB6A3311D4B585E8FA92DF7D35A41F4FCCA7129B921D0ABA174034FCDB36CAE4BB69011E30F7A7A657B1D74C7DCE0CCEB7B01E6F34CE848E3627CAF9D536C3255A80CF5B8064216064E40C7AD67CDF74EC118D8F2D4B6D4A0031A2969ABF5BB2FC4CFDE6E679AA4CB5609C96901D706E9500E94B86D80E4A6A3065227ED8690F5686FF885DC3BB6F1DA7467CEB7D4D42A10B4; __csrf=ca6ddf56d40cc8a27f331f202fe4b326; gdxidpyhxdE=4xfjyEeg4lc3N%5Ch2d%5Cmuya67isI3pZMPzyE5piBKE4MbnmjX8cO%2BUPnScJ7ZVrK8%2FyENi%2FPm%2FUJ%5C7Jt7%2Fu%5CxVq0KD8x%2Bs2uyBrRX6bcW9sjSWg%5Cw%2F7KNEkKk%5C6Mn6dM0bzaQBt%2F06wgBdKtOe3TuWkbDmcE6EvqXOdSnvvjBjs44kdz0%3A1735610638700; __snaker__id=1FPbd4ulJdEVbVUp; ntes_utid=tid._.m%252BLT1NjmAjZAUkFUAAaSMBOdaWzOWutc._.0; sDeviceId=YD-YPiVIvIe3u5EAxABBUfFxyhoxuMxXPie; WNMCID=scyqtk.1735609723331.01.0; WM_NI=AvJ1%2BaTN%2Bars6kp4BqZR6lew0ErnCxDEjplQcna1dpw2o38u%2BYsJZfwf7oZZx3RYpR1b0M2XDa5vbBs0LlSAcWKBQpCU5WBUbXnW%2BM%2BjOjngWravnIJ5CDCtziN4QsN0MW8%3D; WM_NIKE=9ca17ae2e6ffcda170e2e6eea6fb4089be9ab8f74483eb8ab3c55f928f8e83d769869482b1c73985abb6a5e72af0fea7c3b92a83aa86d2aa6b9892e582f179f6b5c0d5c17b9a8efa8de87df49bbe8fc274889ba691ef5ba1b2afd2e77cb5eea1d4bb7fe987bdabd96eb5baf990d952bced9ebaf35af3be00aeb15488bffb97e14ab1f0848dd24ba18985a3d47c818bfbb8c15fa288a2b8aa47e9b6818bed6d95aeaf97ed438aeb8da5c280bab782d5d4798ef083b8bb37e2a3; _ntes_nnid=0abb01037659f4b4a2020921c96bcfd4,1735609718336; _ntes_nuid=0abb01037659f4b4a2020921c96bcfd4; NMTID=00Ob7X1eXe08UIQIk_Bl7cELz7aKHkAAAGQCjtDIA",
}# 音乐id
music_id = 2122122972
song_data = {"ids": f"[{music_id}]","level": "standard","encodeType": "aac","csrf_token": csrf_token
}# 获取js运行的结果
try:efg_obj = js.call("get_efg")res = js.call("decrypt", *(json.dumps(song_data), efg_obj["e"], efg_obj["f"], efg_obj["g"]))
except:print(traceback.format_exc())data = {"params": res["encText"],"encSecKey": res["encSecKey"],
}resp = requests.post(url, headers=headers, data=data)print(resp.status_code)
print(resp.text)music = requests.get(url=resp.json()["data"][0]["url"])
with open(f"{music_id}.m4a", "wb") as f:f.write(music.content)相关文章:
js逆向实战(1)-- 某☁️音乐下载
下载某云音乐源文件.mp4格式 首先随便点进一首歌,如图所示获取该音乐id,然后点击播放键,打开F12进行查询XHR 由此可知,实际请求网址是 https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token「你的token」url需带…...
AIA - APLIC之三(附APLIC处理流程图)
本文属于《 RISC-V指令集基础系列教程》之一,欢迎查看其它文章。 1 APLIC复位 APLIC复位后,其所有状态都变得有效且一致,但以下情况除外: 每个中断域的domaincfg寄存器(spec第 4.5.1 节);可能是machine-level interrupt domain的MSI地址配置寄存器(spec第4.5.3 和4.5…...
React Router 向路由组件传state参数浏览器回退历史页面显示效果问题
昨天在看尚硅谷张天禹老师讲的 React教程p90,老师讲到 React路由的 replace模式和push模式,老师的演示效果与自己本地操作不太一样。 老师的效果:点击查看消息1,消息2,消息3 再点回退,可以依次查看到 消息…...
线程池与并发工具:Java的分身管理器
1 线程池的概念 线程池是一种执行器(Executor),用于在一个后台线程中执行任务。线程池的主要目的是减少在创建和销毁线程时所产生的性能开销。通过重用已经创建的线程来执行新的任务,线程池提高了程序的响应速度,并且提…...
字玩FontPlayer开发笔记8 Tauri2文件系统
字玩FontPlayer开发笔记8 Tauri2文件系统 字玩FontPlayer是笔者开源的一款字体设计工具,使用Vue3 ElementUI开发,源代码: github: https://github.com/HiToysMaker/fontplayer gitee: https://gitee.com/toysmaker/fontplayer 笔记 字玩目…...
头歌python实验:网络安全应用实践3-验证码识别
第1关:简单的验证码识别 本关任务:编写一个能简单识别验证码的小程序。 为了完成本关任务,你需要掌握: 使用 pytesseract 库与 PIL 库解析图片;环境配置;读取图片文本信息。使用 pytesseract 库与 PIL 库解析图片 pytesseract 库可以从图像中提取文本。Tesseract 是一…...
客户案例:基于慧集通(DataLinkX)集成平台的金蝶云星空与HIS系统集成案例--凭证模板的配置(一)
当前的原型客户是一家医院,财务系统使用的是金蝶云星空,需要与医院专用的HIS系统进行集成。本文档主要是介绍其中的凭证模板的配置功能。 凭证模板组件旨在生成凭证前,通过内部整理整合原始单据数据,将其转化为可生成一张凭证的数…...
基于 Python 的大学教室资源管理系统的设计与实现
标题:基于 Python 的大学教室资源管理系统的设计与实现 内容:1.摘要 摘要:随着高校教育的不断发展,教室资源的管理变得越来越重要。为了提高教室资源的利用率,本文设计并实现了一个基于 Python 的大学教室资源管理系统。该系统采用了 B/S 架…...
nginx-灰度发布策略(split_clients)
一. 简述: 基于客户端的灰度发布(也称为蓝绿部署或金丝雀发布)是一种逐步将新版本的服务或应用暴露给部分用户,以确保在出现问题时可以快速回滚并最小化影响的技术。对于 Nginx,可以通过配置和使用不同的模块来实现基于…...
nginx正向代理从安装到使用一网打尽系列(二)使用
一、背景 使用场景大总结,可作为参考手册用 nginx正向代理从安装到使用一网打尽系列(一)安装 nginx正向代理从安装到使用一网打尽系列(二)使用 二、使用场景 1、所有内网应用都不能直接访问外网,但需要…...
Bash Shell的操作环境
目录 1、路径与指令搜寻顺序 2、bash的进站(开机)与欢迎信息:/etc/issue,/etc/motd (1)/etc/issue (2)/etc/motd 3、bash的环境配置文件 (1)login与non-…...
Python爬虫基础——认识网页结构(各种标签的使用)
1、添加<div>标签的代码定义了两个区块的宽度和高度均为100px,边框的格式也相同,只是区块中显示的内容不同; 2、添加<ul>和<ol>标签分别用于定义无序列表和有序列表。<il>标签位于<ul>标签或<ol>标签之…...
如何实现一个充满科技感的官网(二)
背景 在上一篇文章 《如何实现一个充满科技感的官网(一)》 中,我们初步了解了该官网的整体设计,并与大家探讨了它的视觉呈现和用户体验。 我们前期的内部设计偏向简洁,所以开始思考如何提升网站的整体设计感。这些尝…...
GNU链接器简介
GNU链接器简介 1 使用简单程序简介链接脚本1.1 测试程序1.2 编译测试程序1.2.1 不使用链接器编译1.2.1.1 不使用链接器编译1.2.1.2 读取objdump_test 的结构 1.2.2 使用链接器去链接1.2.2.1 链接脚本1.2.2.2 使用链接脚本编译1.2.2.3 读取objdump 的结构 2 链接脚本2.1 基本连接…...
欧几里得算法(简单理解版,非严格证明)
欧几里得算法用于求解两个整数的最大公约数,又称为辗转相除 依据的基本定理: GCD(a,b)GCD(a%b,b) 证明: 对于搞理论的人可能需要会严格证明,但是对于我们一般人而言,只要能理解其原理并记住即可,后者实际上…...
Mac软件介绍之录屏软件Filmage Screen
软件介绍 Filmage Screen 是一款专业的视频录制和编辑软件,适用于 Mac 系统 可以选择4k 60fps,可以选择录制电脑屏幕,摄像头录制,可以选择区域录制。同时也支持,简单的视频剪辑。 可以同时录制电脑麦克风声音 标准…...
Ubuntu cuda-cudnn中断安装如何卸载
文章目录 问题描述解决方法使用强制移除 问题描述 Ubuntu22.04系统,在终端中执行apt insatll安装或dpkg .deb安装时如果强制关闭终端会导致安装失败(安装包会变成iu状态或ru状态,安装成功的应该是ii状态) 此时,无论是…...
CSS——7.CSS注释
<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>css注释</title><link rel"stylesheet" type"text/css" href"a.css"/></head><body><!--头部开始(h…...
鸿蒙APP之从开发到发布的一点心得
引言: 做鸿蒙开发大概有1年左右时间了,从最开始的看官方文档、看B站视频,到后来成功发布两款个人APP(房贷计算极简版、时简时钟 轻喷,谢谢)。简单描述一下里边遇到的坑以及一些经历吧。 学习鸿蒙开发 个…...
某小程序sign签名参数逆向分析
文章目录 1. 写在前面2. 接口分析3. 分析还原 【🏠作者主页】:吴秋霖 【💼作者介绍】:擅长爬虫与JS加密逆向分析!Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Python…...
全球反井钻杆:稳增6.3%,2025年1.19亿,2032年剑指1.87亿
QYResearch调研显示,2025年全球反井钻杆市场规模大约为1.19亿美元,预计2032年将达到1.87亿美元,2026-2032期间年复合增长率(CAGR)为6.3%。地区市场分析:中国市场异军突起从地区层面深入剖析,中国…...
GEO数据挖掘避坑指南:从国内镜像源选择到表达矩阵提取(R语言版)
GEO数据挖掘实战:从镜像加速到表达矩阵的R语言高效处理 每次打开GEO数据库,就像走进了一个巨大的基因表达数据超市——货架上摆满了从癌症研究到神经退行性疾病的各类数据集。但当你兴奋地选中心仪的数据集准备下载时,却常常被缓慢的下载速度…...
ADS2011实战:功率放大器输入输出匹配的Smith圆图优化技巧
1. 从零理解Smith圆图匹配的核心逻辑 第一次接触射频功率放大器设计时,看到Smith圆图上那些密密麻麻的圆圈和曲线,我和大多数初学者一样头皮发麻。直到在ADS2011里亲手拖拽了几次匹配元件,才发现这个看似复杂的工具其实比数学公式直观多了。这…...
Photoshop图层批量导出终极指南:Export-Layers-to-Files-Fast快速上手教程
Photoshop图层批量导出终极指南:Export-Layers-to-Files-Fast快速上手教程 【免费下载链接】Photoshop-Export-Layers-to-Files-Fast This script allows you to export your layers as individual files at a speed much faster than the built-in script from Ado…...
实战教程:星图平台私有化部署Qwen3-VL:30B,实现本地AI多模态能力
实战教程:星图平台私有化部署Qwen3-VL:30B,实现本地AI多模态能力 1. 项目概述与准备工作 1.1 为什么选择Qwen3-VL:30B? Qwen3-VL:30B是目前最强大的开源多模态大模型之一,具备300亿参数规模,能够同时处理文本和图像…...
如何优化HyperDX前端构建速度:Webpack性能调优实战指南
如何优化HyperDX前端构建速度:Webpack性能调优实战指南 【免费下载链接】hyperdx Resolve production issues, fast. An open source observability platform unifying session replays, logs, metrics, traces and errors powered by ClickHouse and OpenTelemetry…...
open_clip 安装与使用实战:从报错解决到模型应用
1. open_clip安装全攻略:从零开始避坑指南 第一次接触open_clip时,我像大多数开发者一样直接pip install走起,结果被各种依赖冲突和模型加载问题折腾得够呛。这里分享我反复验证过的安装方案,帮你避开90%的常见雷区。 先说说环境准…...
[RK3588-Android12] 音频策略深度解析:如何精准配置ES8388喇叭的多媒体播放优先级
1. RK3588平台音频策略问题现象解析 最近在调试RK3588平台的Android12系统时,遇到一个典型的音频问题:使用ES8388 Codec时,喇叭播放多媒体内容无声,但通话和闹钟声音却正常。这个问题困扰了不少开发者,我也是在项目调试…...
Zotero重复文献智能合并方案:解决学术文献库数据冗余问题的自动化工具
Zotero重复文献智能合并方案:解决学术文献库数据冗余问题的自动化工具 【免费下载链接】ZoteroDuplicatesMerger A zotero plugin to automatically merge duplicate items 项目地址: https://gitcode.com/gh_mirrors/zo/ZoteroDuplicatesMerger 在学术研究过…...
DNF私服商业级部署实战:从零到一构建稳定可运营的服务端
1. 商业级DNF私服部署的核心差异 很多朋友可能已经尝试过用一键端搭建个人娱乐用的DNF私服,但商业级部署完全是另一个维度的挑战。去年帮朋友改造一个日均500人在线的私服时,光是处理突发流量就让我连续熬了三个通宵。商业级部署最核心的差异在于&#x…...
