淺測 長亭雷池 WAF “動態防護”

本文首發于 Anyeの小站

前言

雷池 WAF 社區版的更新速度是真快啊,幾乎一周一個小版本,倆月一個大版本,攻城獅們真的狠啊,沒法測了。

|25%xauto

廢話不多說,前兩天看到了 這篇文章,對雷池的“動態防護”功能挺感興趣,特地來試試。

安裝部署

本文以測評為主,不再闡述部署過程,介紹一下我這里的測試環境:

VM1:1Panel 部署 OpenResty,部署項目 Anyeの導航 ,IP(192.168.0.220)

VM2:部署雷池 WAF 社區版,添加站點,開啟“動態防護”,IP(192.168.0.225)

測試

扒取頁面

通常,我會采用這種方式來復刻一個主題,最常用的就是直接從瀏覽器開發人員工具中扒取出頁面的 html,css,js 等文件,來重制主題。

開啟了雷池動態防護的頁面,會有一個解密的過程,其實也就是 js 執行的過程

|100%x100%

|100%x100%

HTML

這個過程極大的延長了頁面的加載時間,大致是 3s 左右。

頁面打開后,對于元素發現頁面構建相同,代表頁面并沒有因為加密而產生變形

|100%x100%

|100%x100%

可見頁面已加密,不過加密也導致 索引 頁面嚴重增大🤣,看看后期有沒有希望繼續優化。

JS

加密了 js 文件嘗試了一下,每次返回的js加密結果都不相同。

|100%x100%

很明顯是進行了混淆,不過經過文本對比后發現了端倪。

這里貼出完整 js 代碼

// 源js文件
/*! * Lazy Load - JavaScript plugin for lazy loading images * * Copyright (c) 2007-2017 Mika Tuupola * * Licensed under the MIT license: *   http://www.opensource.org/licenses/mit-license.php * * Project home: *   https://appelsiini.net/projects/lazyload * * Version: 2.0.0-beta.2 * */
(function(root, factory) {if (typeof exports === "object") {module.exports = factory(root);} else if (typeof define === "function" && define.amd) {define([], factory(root));} else {root.LazyLoad = factory(root);}
}
)(typeof global !== "undefined" ? global : this.window || this.global, function(root) {"use strict";const defaults = {src: "data-src",srcset: "data-srcset",selector: ".lazyload"};/** * Merge two or more objects. Returns a new object. * @private * @param {Boolean}  deep     If true, do a deep (or recursive) merge [optional] * @param {Object}   objects  The objects to merge together * @returns {Object}          Merged values of defaults and options */const extend = function() {let extended = {};let deep = false;let i = 0;let length = arguments.length;/* Check if a deep merge */if (Object.prototype.toString.call(arguments[0]) === "[object Boolean]") {deep = arguments[0];i++;}/* Merge the object into the extended object */let merge = function(obj) {for (let prop in obj) {if (Object.prototype.hasOwnProperty.call(obj, prop)) {/* If deep merge and property is an object, merge properties */if (deep && Object.prototype.toString.call(obj[prop]) === "[object Object]") {extended[prop] = extend(true, extended[prop], obj[prop]);} else {extended[prop] = obj[prop];}}}};/* Loop through each object and conduct a merge */for (; i < length; i++) {let obj = arguments[i];merge(obj);}return extended;};function LazyLoad(images, options) {this.settings = extend(defaults, options || {});this.images = images || document.querySelectorAll(this.settings.selector);this.observer = null;this.init();}LazyLoad.prototype = {init: function() {/* Without observers load everything and bail out early. */if (!root.IntersectionObserver) {this.loadImages();return;}let self = this;let observerConfig = {root: null,rootMargin: "0px",threshold: [0]};this.observer = new IntersectionObserver(function(entries) {entries.forEach(function(entry) {if (entry.intersectionRatio > 0) {self.observer.unobserve(entry.target);self.loadImage(entry.target);}});},observerConfig);this.images.forEach(function(image) {self.observer.observe(image);});},loadAndDestroy: function() {if (!this.settings) {return;}this.loadImages();this.destroy();},loadImage: function(image) {image.onerror = function() {image.onerror = null;image.src = image.srcset = image.dataset.original;};let src = image.getAttribute(this.settings.src);let srcset = image.getAttribute(this.settings.srcset);if ("img" === image.tagName.toLowerCase()) {if (src) {image.dataset.original = image.src;image.src = src;}if (srcset) {image.srcset = srcset;}} else {image.style.backgroundImage = "url(" + src + ")";}},loadImages: function() {if (!this.settings) {return;}let self = this;this.images.forEach(function(image) {self.loadImage(image);});},destroy: function() {if (!this.settings) {return;}this.observer.disconnect();this.settings = null;}};root.lazyload = function(images, options) {return new LazyLoad(images,options);};if (root.jQuery) {const $ = root.jQuery;$.fn.lazyload = function(options) {options = options || {};options.attribute = options.attribute || "data-src";new LazyLoad($.makeArray(this),options);return this;};}return LazyLoad;
});
// 動態防護加密后的js文件
function vgo8rYXzpS() {var YIhUo91Nlh = 99.6174697329428;while (YIhUo91Nlh < 6) {YIhUo91Nlh++}var kJsBQ2iTCw = 77.7991427720637;while (kJsBQ2iTCw < 8) {kJsBQ2iTCw++}var Uv8SujYUUJ = 54.122410119766634;62.94717341414315 + 14.215159769026501;"eCDkWHqKcu";20.29250300507593 + 96.90578776550426;var hKDl2Z6IyR = 2.1154780179250436;while (hKDl2Z6IyR < 9) {hKDl2Z6IyR++}var jJJdYPyWC8 = 96.35369160356686;while (jJJdYPyWC8 < 10) {jJJdYPyWC8++}var q1lUq8lALI = 79.3826780702858;var KSm4kSmK5Q = 16.811363665066132;while (KSm4kSmK5Q < 5) {KSm4kSmK5Q++}while (q1lUq8lALI < 5) {q1lUq8lALI++}var k8jxtioSu1 = 46.12863667479478;if (k8jxtioSu1 < 50)VdgkMuAloP("dbKMKN3DiD");elseVdgkMuAloP("Z_GUlDIf7g");32.61116098968565 + 39.92340222133316;var WOIqRFoBWI = 35.570788142150256;while (WOIqRFoBWI < 10) {WOIqRFoBWI++}var REP52ajkkB = 68.57029249635578;while (REP52ajkkB < 9) {REP52ajkkB++}var UvGT8ugsmm = 77.45257249038768;var c_XLMPoMhw = 70.0508383263844;var oXNng_nyI3 = 61.714023740614785;"f3dzUmlSrt";while (oXNng_nyI3 < 8) {oXNng_nyI3++}"oiou9de1Yg";"jdpOma9ApF";var NeReO5OH2M = 63.89278655453103;while (NeReO5OH2M < 8) {NeReO5OH2M++}var _p_ydR_UZY = 83.88263735619535;var F85mcn2g_m = 17.165604886412726;while (F85mcn2g_m < 10) {F85mcn2g_m++}24.428701219017995 + 36.33105120927406;var E_btPRjrmk = 95.02151619364821;var No5m6438qj = 4.1049208686863246;while (No5m6438qj < 9) {No5m6438qj++}while (E_btPRjrmk < 6) {E_btPRjrmk++}var NW66eJHW18 = 80.32092123501981;if (NW66eJHW18 < 50)VdgkMuAloP("wVsjIS9XQo");elseVdgkMuAloP("GoLW5hTcVj");43.682142399473555 + 22.477837399452866;var UNuZiogsXq = 70.37483244640134;while (UNuZiogsXq < 6) {UNuZiogsXq++}var JyjoRvjvV4 = 60.33084553561216;"PPLO3pqrCR";function VdgkMuAloP() {"CCutBlYuiL";"MgmL5Sv_33";19.82880014765916 + 66.83450544153038;var eH8bW0LeRO = 91.84505170089825;var GGEb99P0LW = 92.75726773787632;"eM_DBnNLNQ";"LTExkL39fU";var ayFeMZ7J9o = 4.08422739984733;var rvzNYoM37B = 42.468405912837106;while (rvzNYoM37B < 6) {rvzNYoM37B++}"YLovxab17O";var dpUNCcw57i = 4.9146145098517575;while (dpUNCcw57i < 10) {dpUNCcw57i++}var ZjzssshCHy = 22.711581319339555;"lsyj2Pu6bi";"mAdio22F97";95.9152148251555 + 18.563789346616783;"Kisq7F_TOW";var EO9rGZSTTK = 53.3184198670574;while (EO9rGZSTTK < 6) {EO9rGZSTTK++}var Lfrg2SayBj = 96.40296951052316;var SR4gkdmFPm = 24.691037844119176;while (SR4gkdmFPm < 7) {SR4gkdmFPm++}"njAS_NShim";"DIoi_JwNCk";var qZALlgtAos = 65.84687374547939;while (qZALlgtAos < 5) {qZALlgtAos++}"i8UnwEQqP2";var mkzN8inJtT = 89.67717243925355;"EXgVlnAkaM";var HGgVbs9bD5 = 56.50704313244045;var myQFrz2kY4 = 54.55344568694437;while (myQFrz2kY4 < 8) {myQFrz2kY4++}var VcC388Sonl = 78.22901590625897;while (VcC388Sonl < 5) {VcC388Sonl++}var EDQM5T4i5x = 58.12080899105871;while (EDQM5T4i5x < 8) {EDQM5T4i5x++}var lS3HRC8N0e = 42.29800294748819;while (lS3HRC8N0e < 5) {lS3HRC8N0e++}}
}
(function(that, a) {var checkF = new RegExp("\\w *\\(\\){.+}");"Saz5menkPn";var checkR = new RegExp("(\\[x|u](\\w){2,4})+");var checkFunction = function checkFunction1() {if (checkR.test(checkFunction.toString())) {f2([2, 15, 12])};return '\x63\x68\x65\x63\x6b\x46\x75\x6e\x63\x74\x69\x6f\x6e'};var f1 = function f1(a) {a.push[a];f2(a)};var f2 = function f2(a) {a.push[a];f1(a)};if (!checkF.test(checkFunction.toString())) {f2([])} else if (checkR.test(checkFunction.toString())) {f2([1, 3, 7])};"ISXAG9bapu";var KOaO2Jk15j = 13.366279497772231;KOaO2Jk15j = 65.44109390187671;return a(that);function f5OTtZ1pUr() {"PFAZrkUkjJ";"yohosCBZku";"czcc_QG98P";var Y7ZMWHKbB5 = 54.61165307973092;while (Y7ZMWHKbB5 < 7) {Y7ZMWHKbB5++}"RAAE3i3HNJ";var yYJU5WMbNs = 81.78463513401672;var Dsj0YbE3nh = 60.12962678573978;while (Dsj0YbE3nh < 8) {Dsj0YbE3nh++}"OrNvH3Vm8U";var FcVeaK_8CJ = 70.65213865609662;var V10P1fXl1e = 93.28700416475893;while (V10P1fXl1e < 7) {V10P1fXl1e++}var _jQaUeEOlz = 50.09958863458343;while (_jQaUeEOlz < 6) {_jQaUeEOlz++}"mkyDT6LuXp";"i_d0Jej01W";93.1178573977863 + 65.0171586053574;"MdcdXdZD8e";var FvwOTr68cW = 63.96686898919228;while (FvwOTr68cW < 5) {FvwOTr68cW++}12.007514883700402 + 67.83201664204582;var lVk87OnDY0 = 10.352772574019035;while (lVk87OnDY0 < 10) {lVk87OnDY0++}"ZIxYt7RDz5";var HOjmKYxZYn = 73.07394273998264;var xf5LYnXM_h = 34.42670716048105;while (xf5LYnXM_h < 7) {xf5LYnXM_h++}25.31980979829108 + 70.92299314386324;53.64987099085665 + 15.95767193794893;81.04615728361688 + 53.03190420900158;"xMyhHs6tqa";var CicbLkYxKL = 71.43209809856342;while (CicbLkYxKL < 9) {CicbLkYxKL++}81.82768180662697 + 44.54696909044475;"a7S1hc6l6e";40.02457556515699 + 50.13884740950273}
}
)(this, function(that) {var EfanXdEsAo = 45.044183852209066;var YiD8rJkjM4 = 60.40560906974519;while (YiD8rJkjM4 < 9) {YiD8rJkjM4++}var SFXCSJnYT5 = 5.6590674829357;function DROWk3baLH() {var zJ2eGCAqG6 = 88.73517894514487;while (zJ2eGCAqG6 < 7) {zJ2eGCAqG6++}"fVZRgjskF7";var imVKfLWElR = 98.4392536479853;var JRZm9ZRXt9 = 65.52198475056669;"B07bldh2rt";94.61531928891331 + 21.79165407508193;"H7umcmyF_g";var kUwyNiUzjX = 48.5975080540464;while (kUwyNiUzjX < 5) {kUwyNiUzjX++}var G5q4i5ptYT = 17.20767169078439;while (G5q4i5ptYT < 9) {G5q4i5ptYT++}"S0RQAJX7ZD";var sbwEsBL3on = 31.621188048769;var Rbqnn2M5lo = 1.6814855430946412;var wXdYUzqLKS = 53.13735728383625;var iIMDA_Qowp = 87.59602310423611;55.899852486295956 + 23.463153124052145;49.64055650210554 + 21.699124979927305}
});
(function(root, factory) {if (typeof exports === "object") {module.exports = factory(root)} else if (typeof define === "function" && define.amd) {define([], factory(root))} else {root.LazyLoad = factory(root)}20.075305793669145 + 96.72088665263502;function mCbgSrID5z() {var ymZDdeQQne = 84.05118287547904;while (ymZDdeQQne < 8) {ymZDdeQQne++}"oeSlUltLf7";var vRcSMA7HZy = 95.63940228416716;while (vRcSMA7HZy < 5) {vRcSMA7HZy++}42.847416356461686 + 64.228599747433;var S4X325xZd0 = 36.8477478357082;var OjdsnE6IgU = 54.6819719737484;while (OjdsnE6IgU < 7) {OjdsnE6IgU++}var tsdIhKV6Tu = 21.849203694513204;"IBEZHnHB9P";var W1xUDNOclb = 97.45176245010938;var qBhKSMePxI = 53.918246237085604;while (qBhKSMePxI < 8) {qBhKSMePxI++}var tG5h3fCZpA = 8.9527278684316;1.8795339533222326 + 85.30147367116075;3.4838274267666733 + 52.70631782675951;var sglVSvKjZv = 13.453736652916252;while (sglVSvKjZv < 9) {sglVSvKjZv++}var bzJ8IfE03K = 72.4963090140686;var IzYpLOgN6D = 1.7126081902147487;86.90125410102027 + 60.096220564929666;55.32420449194843 + 93.21714769547813;15.44123941754805 + 88.74042551968007;"ayjAX7QOFR";"nsviM21tO7";"RGvq8LBnOO";2.5365166268296333 + 58.41895276641477;var NwT9TZgChj = 3.2736264569624316;"ZVRMQfyCrJ";"fwutOlKiEI";var Ejy2yBkKAt = 51.83509013431559;while (Ejy2yBkKAt < 7) {Ejy2yBkKAt++}92.07691206149254 + 13.437580090223227;"qdd7jYm20k";var j2KtWorODN = 42.14264503067741;2.478519996620122 + 58.627727544483704}
}
)(typeof global !== "undefined" ? global : this.window || this.global, function(root) {"use strict";var defaults = {src: "data-src",srcset: "data-srcset",selector: ".lazyload"};var extend = function extend1() {var extended = {};var deep = false;var i = 0;var length = arguments.length;if (Object.prototype.toString.call(arguments[0]) === "[object Boolean]") {deep = arguments[0];i++}var merge = function merge(obj) {for (var prop in obj) {if (Object.prototype.hasOwnProperty.call(obj, prop)) {if (deep && Object.prototype.toString.call(obj[prop]) === "[object Object]") {extended[prop] = extend(true, extended[prop], obj[prop])} else {extended[prop] = obj[prop]}}}};for (; i < length; i++) {var obj = arguments[i];merge(obj)}return extended};function LazyLoad(images, options) {this.settings = extend(defaults, options || {});this.images = images || document.querySelectorAll(this.settings.selector);this.observer = null;this.init()}LazyLoad.prototype = {init: function init() {if (!root.IntersectionObserver) {this.loadImages();return}var self = this;var observerConfig = {root: null,rootMargin: "0px",threshold: [0]};this.observer = new IntersectionObserver(function(entries) {entries.forEach(function(entry) {if (entry.intersectionRatio > 0) {self.observer.unobserve(entry.target);self.loadImage(entry.target)}})},observerConfig);this.images.forEach(function(image) {self.observer.observe(image)})},loadAndDestroy: function loadAndDestroy() {if (!this.settings) {return}this.loadImages();this.destroy()},loadImage: function loadImage(image) {image.onerror = function() {image.onerror = null;image.src = image.srcset = image.dataset.original};var src = image.getAttribute(this.settings.src);var srcset = image.getAttribute(this.settings.srcset);if ("img" === image.tagName.toLowerCase()) {if (src) {image.dataset.original = image.src;image.src = src}if (srcset) {image.srcset = srcset}} else {image.style.backgroundImage = "url(" + src + ")"}},loadImages: function loadImages() {if (!this.settings) {return}var self = this;this.images.forEach(function(image) {self.loadImage(image)})},destroy: function destroy() {if (!this.settings) {return}this.observer.disconnect();this.settings = null}};root.lazyload = function(images, options) {return new LazyLoad(images,options)};if (root.jQuery) {var $ = root.jQuery;$.fn.lazyload = function(options) {options = options || {};options.attribute = options.attribute || "data-src";new LazyLoad($.makeArray(this),options);return this}}98.21293314139757 + 7.022202427695869;return LazyLoad;var zb5YrDEzX8 = 49.67145292566205;function EMQ2TiywJ2() {"kDDG4hcurX";"LmMQDl5Guf";"H1d2hSNdZu";"vR3uU0dztV";"BYg6Cwwew1";"Z7Cgb85The";var vqCn2LKHiQ = 79.8849526204871;while (vqCn2LKHiQ < 6) {vqCn2LKHiQ++}"HzKhtzFo0S";var Ruo3QF3HKv = 57.10873587557603;while (Ruo3QF3HKv < 8) {Ruo3QF3HKv++}var NIVPEUabT_ = 25.838978101412078;var pmvJIgXrA7 = 41.71629707156116;while (pmvJIgXrA7 < 7) {pmvJIgXrA7++}var cTqhNJmnqp = 7.679109504729966;var Xkldnu7eiS = 89.26080892492617;while (Xkldnu7eiS < 8) {Xkldnu7eiS++}var Iq6adjqOVj = 86.04734679658776;while (Iq6adjqOVj < 7) {Iq6adjqOVj++}var TyC7F0mXPj = 57.405394830228786;while (TyC7F0mXPj < 7) {TyC7F0mXPj++}var q7oS54FoCf = 19.715578974920984;6.354381716758419 + 48.514464467999424;var JPOOCo51Cg = 94.50513995137923;18.85838453981073 + 55.22787281970704;"rUww9Es4UQ"}
});

可見該加密方式采用了:

  • 變量名和函數名替換:將原有的變量名和函數名替換為難以理解的字符或字符串,例如vgo8rYXzpSYIhUo91Nlh等。
  • 字符串混淆:將代碼中的字符串通過某些算法轉換為難以閱讀的形式。
  • 控制流改變:通過添加無意義的循環、條件判斷等,改變代碼的控制流,使得代碼執行過程變得復雜。
  • 代碼拆分:將代碼拆分為多個部分,并通過某些機制動態地組合執行。

可見還是較為容易反混淆的,期待后期加強。

python 爬取

根據 官方文檔 所述,動態防護還是為了可以更好地阻止爬蟲和攻擊自動化程序的分析,那么就嘗試編寫一段python代碼來進行 HTML 內容爬取測試。

比如爬取 本站導航站,這里使用 Microsoft 的 playwright 庫

import asyncio
from playwright.async_api import async_playwrightasync def scrape_data():async with async_playwright() as p:browser = await p.chromium.launch(headless=True)page = await browser.new_page()# 加載頁面await page.goto('http://192.168.0.220')# 等待頁面加載完成await page.wait_for_load_state('networkidle')# 提取鏈接、圖標和描述items = await page.query_selector_all('.list-item.block')data = []for item in items:link = await item.query_selector('a.list-content')if link:href = await link.get_attribute('href')title = await link.query_selector('.list-title')desc = await link.query_selector('.list-desc')img = await item.query_selector('img')data.append({'link': href,'title': await title.inner_text() if title else None,'desc': await desc.inner_text() if desc else None,'icon': await img.get_attribute('src') if img else None,})await browser.close()return data# 運行
async def main():data = await scrape_data()for entry in data:print(entry)asyncio.run(main())

源站執行爬取后輸出:

|100%x100%

雷池防護后:

|100%x100%

效果明顯,不過,感覺還是有繞過的空間呀?試試瀏覽器有頭模式?

import asyncio
from playwright.async_api import async_playwrightasync def scrape_data():async with async_playwright() as p:# 指定瀏覽器路徑并啟用有頭模式browser = await p.chromium.launch(headless=False,  # 設置為 False 以顯示瀏覽器窗口executable_path="C:\\Users\\Anye\\AppData\\Local\\Chromium\\Application\\chrome.exe")page = await browser.new_page()# 加載本地服務器上的頁面await page.goto('http://192.168.0.225/')# 手動處理人機驗證print("請手動處理頁面上的人機驗證...")await page.wait_for_selector('.list-item.block', timeout=0)  # 等待頁面加載完成,沒有超時限制# 提取鏈接、圖標和描述items = await page.query_selector_all('.list-item.block')data = []for item in items:link = await item.query_selector('a.list-content')if link:href = await link.get_attribute('href')title = await link.query_selector('.list-title')desc = await link.query_selector('.list-desc')img = await item.query_selector('img')data.append({'link': href,'title': await title.inner_text() if title else None,'desc': await desc.inner_text() if desc else None,'icon': await img.get_attribute('src') if img else None,})await browser.close()return data# 運行
async def main():data = await scrape_data()for entry in data:print(entry)asyncio.run(main())

結果:成功獲取內容

|100%x100%

既然這樣,那豈不是等待解密后就可以獲取內容了,那么等待5秒試試?

import asyncio
from playwright.async_api import async_playwrightasync def scrape_data():async with async_playwright() as p:browser = await p.chromium.launch(headless=True)page = await browser.new_page()# 加載頁面await page.goto('http://192.168.0.225')# 等待頁面加載完成await page.wait_for_load_state('networkidle')# 等待5秒await page.wait_for_timeout(5000)# 提取鏈接、圖標和描述items = await page.query_selector_all('.list-item.block')data = []for item in items:link = await item.query_selector('a.list-content')if link:href = await link.get_attribute('href')title = await link.query_selector('.list-title')desc = await link.query_selector('.list-desc')img = await item.query_selector('img')data.append({'link': href,'title': await title.inner_text() if title else None,'desc': await desc.inner_text() if desc else None,'icon': await img.get_attribute('src') if img else None,})await browser.close()return data# 運行
async def main():data = await scrape_data()for entry in data:print(entry)asyncio.run(main())

|100%x100%

成功獲取。

雷池開發別打我,HTML 確實不太好加密

不過目前來講確實可以攔截大部分爬蟲的爬取,正常爬蟲不會長時間等待頁面加載,也不會用有頭模式。

測試++

經測試,開啟 人機驗證 后,是可以有效攔截爬蟲獲取內容。

|100%x100%

|100%x100%

不過還是希望雷池開發大大可以繼續研究研究如何加強“動態防護”的算法😘。

后記

不讓黑客,越雷池一步。

本次測試為內部測試環境,請勿用于黑客攻擊行為。后期雷池也會加強加密算法,保護 WEB 安全。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/21748.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/21748.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/21748.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Android應用的基本構造及威脅(apk)

目錄 APK文件是什么 apk文件解壓后的目錄結構 apk文件的存儲位置

去掉el-table表頭右側類名是gutter,width=17px的空白區域(包括表頭樣式及表格奇偶行樣式和表格自動滾動)

代碼如下&#xff1a; <el-table:data"tableData"ref"scroll_Table":header-cell-style"getRowClass":cell-style"styleBack"height"350px"style"width: 100%"><el-table-column prop"id" l…

Scrum團隊在迭代中如何處理計劃外的工作

認為 Scrum 團隊不做計劃其實是一個誤區&#xff0c;實際上很多 Scrum 團隊在沖刺計劃會議以及在細化工作項時均會進行詳細規劃。此外&#xff0c;他們還會創建一個路線圖&#xff0c;以便顯示他們在多個沖刺中的計劃。 Scrum 團隊需要經常進行計劃&#xff0c;以便在不斷變化…

linux學習:進程

目錄 例子1 獲取當前進程的進程標識符 例子2 創建一個新的子進程 例子3 展示了父進程和子進程的進程標識符 例子4 區分父進程和子進程 例子5 區分父進程和子進程的行為 例子6 比較進程標識符來區分父進程和子進程 例子7 子進程如何修改一個變量&…

混合動力電動汽車介紹(二)

接續前一章內容&#xff0c;本篇文章介紹混合動力汽車串聯、并聯和混聯的系統組成和工作原理。 一、串聯混合動力電動汽車的系統組成和工作原理 上圖為串聯混合動力電動汽車的結構簡圖。汽車由電動機-發電機驅動行駛&#xff0c;電機控制器的動力來自油箱-發動機-發電機-發電機…

Python 爬蟲零基礎:探索網絡數據的神秘世界

Python 爬蟲零基礎&#xff1a;探索網絡數據的神秘世界 在數字化時代&#xff0c;網絡數據如同無盡的寶藏&#xff0c;等待著我們去發掘。Python爬蟲&#xff0c;作為獲取這些數據的重要工具&#xff0c;正逐漸走進越來越多人的視野。對于零基礎的學習者來說&#xff0c;如何入…

基于Spring Boot框架的分頁查詢和文件上傳

分頁查詢 分析 要想從數據庫中進行分頁查詢&#xff0c;我們要使用LIMIT關鍵字&#xff0c;格式為&#xff1a;limit 開始索引 每頁顯示的條數 假設一頁想展示10條數據 查詢第1頁數據的SQL語句是&#xff1a; select * from emp limit 0,10; 查詢第2頁數據的SQL語句是&…

【Pytest官方文檔翻譯及學習】2.2 如何在測試中編寫和報告斷言

目錄 2.2 如何在測試中編寫和報告斷言 2.2.1 使用assert語句斷言 2.2.2 關于預期異常的斷言 2.2.3 關于預期警告的斷言 2.2.4 應用上下文相關的比較 2.2.5 為失敗的斷言定義自己的解釋 2.2.6 斷言內省細節 2.2 如何在測試中編寫和報告斷言 2.2.1 使用assert語句斷言 p…

6、架構-服務端緩存

為系統引入緩存之前&#xff0c;第一件事情是確認系統是否真的需要緩 存。從開發角度來說&#xff0c;引入緩存會提 高系統復雜度&#xff0c;因為你要考慮緩存的失效、更新、一致性等問題&#xff1b;從運維角度來說&#xff0c;緩存會掩蓋一些缺 陷&#xff0c;讓問題在更久的…

npm徹底清理緩存

在使用npm過程中&#xff0c;肯定會遇到清緩存的情況&#xff0c;網上的命令一般為 npm cache clear --force有時筆者在清理緩存之后npm install依然失敗&#xff0c;仔細發現&#xff0c;執行該命令之后npm報了一個警告 npm WARN using --force Recommended protections dis…

代碼隨想錄算法訓練營第27天|● 39. 組合總和● 40.組合總和II● 131.分割回文串

組合總和 題目鏈接 39. 組合總和 - 力扣&#xff08;LeetCode&#xff09; 代碼&#xff1a; class Solution {public List<List<Integer>> res new ArrayList<>();public List<Integer> list new ArrayList<>();public int sum 0;/**…

在nginx中配置反向代理

在nginx中配置反向代理&#xff0c;需要使用proxy_pass指令。以下是一個簡單的nginx反向代理配置示例&#xff1a; server {listen 80;server_name example.com;location / {proxy_pass http://backend_server;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote…

LoadRunner 錄制腳本時提示無Internet訪問/加載慢,如何解決?

LoadRunner 錄制腳本時提示無Internet訪問/加載慢&#xff0c;如何解決&#xff1f; 在使用LoadRunner 12.02 進行錄制腳本時提示無Internet訪問&#xff0c;這是如下圖&#xff1a; 翻譯中文如下&#xff1a; 這里&#xff0c;我認為大家應該都已經點過yes了&#xff0c;但是…

python結構化模式匹配switch-case,Python 3.10中引入,Python的模式匹配(pattern matching)語法

增加了采用模式加上相應動作的 match 語句 和 case 語句 的形式的結構化模式匹配。 模式由序列、映射、基本數據類型以及類實例構成。 模式匹配使得程序能夠從復雜的數據類型中提取信息、根據數據結構實現分支&#xff0c;并基于不同的數據形式應用特定的動作。 語法與操作 模…

Linux下配置Pytorch

1.Anaconda 1.1虛擬環境創建 2.Nvidia驅動 3.CUDA驅動安裝 4.Pytorch安裝 具體的步驟如上&#xff1a;可參考另一位博主的博客非常詳細&#xff1a; Linux服務器配置PythonPyTorchCUDA深度學習環境_linux cuda環境配置-CSDN博客https://blog.csdn.net/NSJim/article/detai…

極海APM32F072用Keil5燒錄失敗Error: Flash Download failed -“Cortex-MO+“

在用Keil5燒錄時&#xff0c;出現錯誤彈窗&#xff0c;大概長這樣&#xff1a; 檢查了一圈設置&#xff0c;都搞不好。 先用J-Flash&#xff0c;顯示讀寫保護&#xff08;未截圖&#xff09;&#xff0c;會跳出界面讓選擇是否解除讀寫保護&#xff1a; 1.點擊允許讀操作YES&am…

DNF手游攻略:0氪攻略,轉職技巧與避坑指南!

在DNF手游的冒險旅程中&#xff0c;角色的轉職是一次重要的成長經歷。通過轉職&#xff0c;玩家可以獲得全新的技能和屬性&#xff0c;提升自己在地下城中的戰斗力。本文將為您介紹轉職后的關鍵技巧和日常任務&#xff0c;幫助您更好地適應新的職業身份&#xff0c;成為地下城中…

Python從0到100(二十九):requests模塊處理cookie

1 爬蟲中使用cookie 為了能夠通過爬蟲獲取到登錄后的頁面&#xff0c;或者是解決通過cookie的反扒&#xff0c;需要使用request來處理cookie相關的請求 1.1 爬蟲中使用cookie的利弊 帶上cookie的好處 能夠訪問登錄后的頁面能夠實現部分反反爬 帶上cookie的壞處 一套cookie往往…

數據庫與低代碼開發:技術革新與應用實踐

在數字化時代&#xff0c;企業對軟件開發的需求日益增長&#xff0c;同時對開發效率和成本控制的要求也越來越高。在這樣的背景下&#xff0c;低代碼開發平臺應運而生&#xff0c;它允許開發者通過圖形界面和配置化操作&#xff0c;快速構建應用程序&#xff0c;而無需編寫大量…

【設計模式】JAVA Design Patterns——Monitor(監視器模式)

&#x1f50d;目的 主要目的是為多個線程或進程提供一種結構化和受控的方式來安全地訪問和操作共享資源&#xff0c;例如變量、數據結構或代碼的關鍵部分&#xff0c;而不會導致沖突或競爭條件。 &#x1f50d;解釋 通俗描述 監視器模式用于強制對數據進行單線程訪問。 一次只允…