Jsoup與HtmlUnit:兩大Java爬蟲工具對比解析

?Jsoup:HTML解析利器

  • 定位:專注HTML解析的輕量級庫(也就是快,但動態頁面無法抓取)

  • 核心能力

    • DOM樹解析與CSS選擇器查詢

    • HTML凈化與格式化

    • 支持元素遍歷與屬性提取

  • 應用場景:靜態頁面數據抽取、內容清洗

    public static Document getJsoupDoc(String url, Integer frequency, Integer connectTimeout) {Document document = null;try {if(connectTimeout==null){document = Jsoup.connect(url).ignoreContentType(true).get();}else{document = Jsoup.connect(url).ignoreContentType(true).maxBodySize(0).timeout(connectTimeout).get();}} catch (Exception e) {document = null;}if (document == null && frequency < 3) {frequency = frequency + 1;try {Thread.sleep(100);} catch (InterruptedException e) {log.error("休眠異常:" + e.getMessage(), e);}document = getJsoupDoc(url, frequency, connectTimeout);}return initUrl(url,document);}

    ?HtmlUnit:無頭瀏覽器引擎

    • 定位:支持JavaScript的全功能瀏覽器模擬器(js動態數據的加載)

    • 核心能力

      • 執行復雜AJAX請求

      • 模擬用戶交互(點擊/表單提交)

      • 支持Cookie管理和頁面跳轉

    • 典型場景:動態網頁抓取、自動化測試

      /*** @param url      爬蟲鏈接* @param waitTime 等待時間* @return*/public static Document getDynamicCrawlersDocument(String url, Integer waitTime, boolean javaScriptEnabled) {Document document = null;try (WebClient browser = new WebClient()) {//解決動態頁面抓取不到信息問題browser.getOptions().setCssEnabled(false);browser.getOptions().setJavaScriptEnabled(javaScriptEnabled);browser.getOptions().setThrowExceptionOnScriptError(false);browser.getOptions().setUseInsecureSSL(true);// 設置自定義的錯誤處理類browser.setJavaScriptErrorListener(new MyJSErrorListener());HtmlPage page = null;page = browser.getPage(url);// 等待后臺腳本執行時間browser.waitForBackgroundJavaScript(waitTime);String pageAsXml = page.asXml();document = Jsoup.parse(pageAsXml.replaceAll("\\<\\?xml.*?\\?>", ""));document.setBaseUri(url);} catch (ScriptException e) {log.error("getDynamicCrawlersDocument頁面:{}     JavaScript 異常:{}", url, e.getMessage());return initUrl(url,document);} catch (UnknownHostException e) {log.error("getDynamicCrawlersDocument頁面:{}     無法解析或找到指定的主機名:{}", url, e.getMessage());return initUrl(url,document);} catch (FailingHttpStatusCodeException e) {log.error("getDynamicCrawlersDocument頁面:{}     HTTP 狀態異常:{}", url, e.getStatusCode());return initUrl(url,document);} catch (Exception e) {log.error("getDynamicCrawlersDocument頁面:{}    獲取頁面異常:{}", url, e.getMessage());return initUrl(url,document);}return initUrl(url,document);}

      核心優勢對比

      特性JsoupHtmlUnit
      解析速度?? 毫秒級響應? 需加載完整頁面資源
      JS支持? 不執行任何腳本? 完整JavaScript引擎
      內存占用🟢 10MB級內存消耗🔴 100MB+內存需求
      學習曲線🟢 半天掌握核心API🟡 需理解瀏覽器事件模型
      反爬繞過? 基礎Header支持? 模擬真實瀏覽器指紋
    • 實戰場景選擇指南

      ? 首選Jsoup的情況

      • 目標數據存在于初始HTML中(靜態頁面)

      • 需要高頻抓取(>1000次/分鐘)

      • 服務器資源受限(云函數/邊緣計算)

      • 快速原型開發需求

    • ? 必須HtmlUnit的場景

      • 頁面依賴AJAX動態加載(js數據請求)

      • 需要登錄Cookie保持

      • 涉及表單交互操作

      • 需解析Shadow DOM內容

結語

Jsoup與HtmlUnit代表了Java爬蟲的兩個技術維度:極致效率完整模擬。理解二者的設計哲學,根據實際場景靈活選用甚至組合使用(如用HtmlUnit獲取初始頁面后用Jsoup解析),往往能取得最佳效果。在日益復雜的反爬機制下,合理選擇工具將成為數據抓取成功的關鍵。

完整代碼工具類

package com.zzkj.zei.utils;import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSON;
import com.zzkj.zei.pojo.system.SysSite;
import com.zzkj.zei.utils.spider.SpiderUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.htmlunit.BrowserVersion;
import org.htmlunit.FailingHttpStatusCodeException;
import org.htmlunit.ScriptException;
import org.htmlunit.WebClient;
import org.htmlunit.html.HtmlAnchor;
import org.htmlunit.html.HtmlPage;
import org.htmlunit.javascript.DefaultJavaScriptErrorListener;
import org.jetbrains.annotations.NotNull;
import org.jsoup.HttpStatusException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;import java.io.IOException;
import java.net.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** FileName: JsoupHtmlUintUtils* Author: wzk* Date:2024/11/8 9:32*/
@Slf4j
public class JsoupHtmlUintUtils {/*** 動態檢測** @param url 爬蟲鏈接* @return*/public static Document getDynamicCrawlersDocument(String url) {Document document = null;//解決動態頁面抓取不到信息問題WebClient browser = new WebClient(BrowserVersion.CHROME);browser.getOptions().setCssEnabled(false);browser.getOptions().setJavaScriptEnabled(false);browser.getOptions().setThrowExceptionOnScriptError(false);// 允許使用不安全的 SSLbrowser.getOptions().setUseInsecureSSL(true);// 設置自定義的錯誤處理類browser.setJavaScriptErrorListener(new MyJSErrorListener());HtmlPage page = null;try {page = browser.getPage(url);// 等待后臺腳本執行時間browser.waitForBackgroundJavaScript(1000);String pageAsXml = page.asXml();document = Jsoup.parse(pageAsXml);} catch (ScriptException e) {log.info("頁面:{}     JavaScript 異常:{}", url, e.getMessage());} catch (FailingHttpStatusCodeException e) {log.info("頁面:{}     HTTP 狀態異常:{}", url, e.getStatusCode());} catch (UnknownHostException e) {log.info("頁面:{}     無法解析或找到指定的主機名:{}", url, e.getMessage());} catch (Exception e) {log.error("頁面:{}    獲取頁面異常:{}", url, e.getMessage());}return initUrl(url,document);}/*** @param url      爬蟲鏈接* @param waitTime 等待時間* @return*/public static Document getDynamicCrawlersDocument(String url, Integer waitTime, boolean javaScriptEnabled) {Document document = null;try (WebClient browser = new WebClient()) {//解決動態頁面抓取不到信息問題browser.getOptions().setCssEnabled(false);browser.getOptions().setJavaScriptEnabled(javaScriptEnabled);browser.getOptions().setThrowExceptionOnScriptError(false);browser.getOptions().setUseInsecureSSL(true);// 設置自定義的錯誤處理類browser.setJavaScriptErrorListener(new MyJSErrorListener());HtmlPage page = null;page = browser.getPage(url);// 等待后臺腳本執行時間browser.waitForBackgroundJavaScript(waitTime);String pageAsXml = page.asXml();document = Jsoup.parse(pageAsXml.replaceAll("\\<\\?xml.*?\\?>", ""));document.setBaseUri(url);} catch (ScriptException e) {log.error("getDynamicCrawlersDocument頁面:{}     JavaScript 異常:{}", url, e.getMessage());return initUrl(url,document);} catch (UnknownHostException e) {log.error("getDynamicCrawlersDocument頁面:{}     無法解析或找到指定的主機名:{}", url, e.getMessage());return initUrl(url,document);} catch (FailingHttpStatusCodeException e) {log.error("getDynamicCrawlersDocument頁面:{}     HTTP 狀態異常:{}", url, e.getStatusCode());return initUrl(url,document);} catch (Exception e) {log.error("getDynamicCrawlersDocument頁面:{}    獲取頁面異常:{}", url, e.getMessage());return initUrl(url,document);}return initUrl(url,document);}private static List<Document> getDynamicCrawlersDocument(String url, Integer waitTime) {List<Document> documents = new ArrayList<>();HtmlPage oldPage = null;try (WebClient browser = new WebClient()) {//解決動態頁面抓取不到信息問題browser.getOptions().setCssEnabled(false);browser.getOptions().setJavaScriptEnabled(true);browser.getOptions().setThrowExceptionOnScriptError(false);browser.getOptions().setUseInsecureSSL(true);// 設置自定義的錯誤處理類browser.setJavaScriptErrorListener(new MyJSErrorListener());HtmlPage page = null;page = browser.getPage(url);oldPage = page;// 等待后臺腳本執行時間browser.waitForBackgroundJavaScript(waitTime);Document document;document = getDocuments(url, page);documents.add(document);while (true) {HtmlAnchor nextButton = page.getFirstByXPath("//a[contains(text(), '下一頁')]");if (nextButton == null || nextButton.getAttribute("class").contains("disabled")) {break; // No more pages}page = nextButton.click();browser.waitForBackgroundJavaScript(waitTime);if (page.equals(oldPage) && !page.getUrl().toString().equals(url)) {break;}oldPage = page;document = getDocuments(url, page);documents.add(document);}} catch (ScriptException e) {log.error("getDynamicCrawlersDocument頁面:{}     JavaScript 異常:{}", url, e.getMessage());} catch (UnknownHostException e) {log.error("getDynamicCrawlersDocument頁面:{}     無法解析或找到指定的主機名:{}", url, e.getMessage());} catch (FailingHttpStatusCodeException e) {log.error("getDynamicCrawlersDocument頁面:{}     HTTP 狀態異常:{}", url, e.getStatusCode());} catch (Exception e) {log.error("getDynamicCrawlersDocument頁面:{}    獲取頁面異常:{}", url, e.getMessage());}return documents;}private static @NotNull Document getDocuments(String url, HtmlPage page) {String pageAsXml = page.asXml();Document document = Jsoup.parse(pageAsXml.replaceAll("\\<\\?xml.*?\\?>", ""));document.setBaseUri(url);return initUrl(url,document);}public static List<Document> getDocuments(String url, Integer isDynamic) {List<Document> list;if (isDynamic == 1) {list = getDynamicCrawlersDocument(url, 1000);} else {list = getJsoupDoc(url);}return list;}public static Document getDocument(String url, Integer isDynamic) {Document document;if (isDynamic == 1) {document = getDynamicCrawlersDocument(url, 1000, true);} else {document = getJsoupDoc(url, 1, null);}return initUrl(url,document);}/*** @param url 爬蟲鏈接* @return*/public static Document getJsoupDoc(String url, Integer frequency, Integer connectTimeout) {Document document = null;try {if(connectTimeout==null){document = Jsoup.connect(url).ignoreContentType(true).get();}else{document = Jsoup.connect(url).ignoreContentType(true).maxBodySize(0).timeout(connectTimeout).get();}} catch (Exception e) {document = null;}if (document == null && frequency < 3) {frequency = frequency + 1;try {Thread.sleep(100);} catch (InterruptedException e) {log.error("休眠異常:" + e.getMessage(), e);}document = getJsoupDoc(url, frequency, connectTimeout);}return initUrl(url,document);}private static List<Document> getJsoupDoc(String url) {List<Document> list = new ArrayList<>();Document document = getJsoupDoc(url, 1, null);list.add(document);return list;}public static String getRedirectUrl(String url) {log.info("getRedirectUrl-------------------url---------------" + url);String redirectUrl = "";//設置模擬瀏覽器try (WebClient webClient = new WebClient(BrowserVersion.CHROME)) {//是否等待頁面javaScrpit加載webClient.getOptions().setJavaScriptEnabled(true);webClient.getOptions().setRedirectEnabled(true);// js運行錯誤時,是否拋出異常webClient.getOptions().setThrowExceptionOnScriptError(false);webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);// 設置連接超時時間webClient.getOptions().setTimeout(200);// HtmlUnitredirectUrl = webClient.getPage(url).getUrl().toString();} catch (FailingHttpStatusCodeException | IOException e) {log.error(url + "獲取重定向網站失敗1:" + e.getMessage(), e);} catch (Exception e) {log.error(url + "獲取重定向網站失敗2:" + e.getMessage(), e);}return redirectUrl;}/*** 獲取重定向url** @param hrefUrl     鏈接地址* @param metaTagsUrl 元標簽地址* @param sysSite     站點實體* @return*/public static String getRedirectUrl(String hrefUrl, String metaTagsUrl, SysSite sysSite) {String redirectUrl = "";try {if (metaTagsUrl.startsWith("./") && SpiderUtils.isNode(hrefUrl, sysSite)) {if (hrefUrl.endsWith("/")) {redirectUrl = hrefUrl + metaTagsUrl.substring(2);} else {redirectUrl = hrefUrl + metaTagsUrl.substring(1);}} else if (metaTagsUrl.startsWith("./") && hrefUrl.endsWith(".html")) {hrefUrl = hrefUrl.substring(0, hrefUrl.lastIndexOf("/"));metaTagsUrl = metaTagsUrl.substring(1);redirectUrl = hrefUrl + metaTagsUrl;} else if ("../".equals(metaTagsUrl) && SpiderUtils.isNode(hrefUrl, sysSite)) {if (hrefUrl.endsWith("/")) {hrefUrl = hrefUrl.substring(0, hrefUrl.length() - 1);}redirectUrl = hrefUrl.substring(0, hrefUrl.lastIndexOf('/'));} else if ("/".equals(metaTagsUrl)) {redirectUrl = sysSite.getSiteDomain();} else {//SpiderUtils.saveLogText("需要獲取重定向以后的url--------------------hrefUrl:"+hrefUrl+"--------metaTagsUrl:"+metaTagsUrl);redirectUrl = JsoupHtmlUintUtils.getRedirectUrl(hrefUrl);//SpiderUtils.saveLogText("需要獲取重定向以后的url-----------返回結果---------redirectUrl:"+redirectUrl);}} catch (Exception e) {log.error("獲取的url失敗:" + e.getMessage(), e);}return redirectUrl;}/*** 獲取原標簽的url** @param refreshMeta* @return*/public static String getMetaTagsUrl(Element refreshMeta) {String refreshUrl = "";try {if (refreshMeta != null) {String patternString = "http-equiv\\s*=\\s*\"?Refresh\"?\\s*[\\s;]*content\\s*=\\s*\"?(\\d+);\\s*url\\s*=\\s*(\"?)(.*?)\\2\"";Pattern pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE);Matcher matcher = pattern.matcher(refreshMeta.html());if (matcher.find()) {refreshUrl = matcher.group(3);}}} catch (Exception e) {log.error("獲取元標簽的url失敗:" + e.getMessage(), e);}return refreshUrl;}/*** 獲取鏈接的狀態碼** @param url 爬蟲鏈接* @return*/public static Integer getUrlResponseCode(String url, Integer frequency) {int statusCode;try (HttpResponse response = HttpRequest.head(url).setConnectionTimeout(1000).execute()) {//使用hutool方法獲取狀態碼statusCode = response.getStatus();if (statusCode >= 400 && frequency < 3) {frequency = frequency + 1;try {Thread.sleep(200);} catch (InterruptedException e) {log.error("休眠異常:" + e.getMessage(), e);}statusCode = getUrlResponseCode(url, frequency);}} catch (Exception e) {log.error(url+"-----獲取url的狀態碼失敗:" + e.getMessage(), e);statusCode = 500;}return statusCode;}/*** 靜態爬蟲** @param url* @return*/private Document getStaticCrawlers(String url) {Document document = null;try {document = Jsoup.connect(url).timeout(5000).get();} catch (HttpStatusException e) {// 后臺異常處理if ((e.getStatusCode() + "").startsWith("5")) {try {Thread.sleep(2000); // 睡眠2秒document = Jsoup.connect(url).timeout(5000).get();} catch (IOException ex) {ex.getMessage();} catch (InterruptedException ex) {throw new RuntimeException(ex);}}} catch (Exception e) {e.printStackTrace();}return initUrl(url,document);}private Document getStaticCrawlers(String url, Integer waitTime) {Document document = null;try {document = Jsoup.connect(url).timeout(waitTime).get();} catch (HttpStatusException e) {// 后臺異常處理if ((e.getStatusCode() + "").startsWith("5")) {try {Thread.sleep(2000); // 睡眠2秒document = Jsoup.connect(url).timeout(waitTime).get();} catch (IOException ex) {ex.getMessage();} catch (InterruptedException ex) {throw new RuntimeException(ex);}}} catch (Exception e) {}return initUrl(url,document);}/*** 初始化Document中的相對路徑為絕對路徑* @param sourceUrl 基準URL,用于解析相對路徑* @param document Jsoup解析的Document對象* @return 處理后的Document* @throws IllegalArgumentException 如果基準URL無效*/public static Document initUrl(String sourceUrl, Document document) {try{if (ObjectUtils.isNotEmpty(document)){URI baseUri;try {baseUri = new URI(sourceUrl);} catch (URISyntaxException e) {throw new IllegalArgumentException("鏈接處理異常: " + sourceUrl, e);}Elements aList = document.select("a");for (Element element : aList) {String href = element.attr("href");// 跳過空或無效的href屬性if (href == null || href.isEmpty()) {continue;}//是javascript:void(0)類似這樣的非法鏈接if (SpiderUtils.filterJavaScript(href)) {continue;}//不符合url規則if (SpiderUtils.illegalUrl(href)) {continue;}try {URI resolvedUri = baseUri.resolve(href);element.attr("href", resolvedUri.toString());} catch (IllegalArgumentException e) {// 可選:記錄解析失敗的情況log.error("無法解析鏈接 '" + href + "': " + e.getMessage());}}}} catch (Exception e){log.info("document初始化鏈接異常:",e.getMessage(),e);}return document;}static class MyJSErrorListener extends DefaultJavaScriptErrorListener {@Overridepublic void scriptException(HtmlPage page, ScriptException scriptException) {}@Overridepublic void timeoutError(HtmlPage page, long allowedTime, long executionTime) {}@Overridepublic void malformedScriptURL(HtmlPage page, String url, MalformedURLException malformedURLException) {}@Overridepublic void loadScriptError(HtmlPage page, URL scriptUrl, Exception exception) {}@Overridepublic void warn(String message, String sourceName, int line, String lineSource, int lineOffset) {}}}

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

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

相關文章

小白成長之路-vim編輯

文章目錄 Vim一、命令模式二、插入模式3.a:進入插入模式&#xff0c;在當前光標的后一個字符插入![在這里插入圖片描述](https://i-blog.csdnimg.cn/direct/fd293c3832ed49e2974abfbb63eeb5bb.png)4.o: 在當前光標的下一行插入5.i:在當前光標所在字符插入&#xff0c;返回命令模…

[redis進階六]詳解redis作為緩存分布式鎖

目錄 一 什么是緩存 緩存總結板書: 二 使?Redis作為緩存 三 緩存的更新策略 1) 定期?成 2) 實時?成 四 面試重點:緩存預熱,緩存穿透,緩存雪崩 和緩存擊穿 1)緩存預熱 2)緩存穿透 3)緩存雪崩 4)緩存擊穿 五 分布式鎖 板書: 1)什么是分布式鎖 2)分布式鎖的基…

【MySQL】數據表插入數據

個人主頁&#xff1a;Guiat 歸屬專欄&#xff1a;MySQL 文章目錄 1. 插入數據概述1.1 插入數據的重要性1.2 插入數據的基本原則 2. 基本插入語句2.1 INSERT INTO語法2.2 插入多行數據2.3 不指定列名的插入2.4 插入NULL和默認值 3. 高級插入技術3.1 使用子查詢插入數據3.2 IGNOR…

軟考-軟件設計師中級備考 14、刷題 算法

一、考點歸納 1&#xff09;排序 2、查找 3、復雜度 4、經典問題 0 - 1 背包動態規劃0 - 1 背包問題具有最優子結構性質和重疊子問題性質。通過動態規劃可以利用一個二維數組來記錄子問題的解&#xff0c;避免重復計算&#xff0c;從而高效地求解出背包能裝下的最大價值。分…

【阿里云】阿里云 Ubuntu 服務器無法更新 systemd(Operation not permitted)的解決方法

零、前言 目前正在使用的Ubuntu服務器中&#xff0c;僅阿里云&#xff08;不止一臺&#xff09;出現了這個問題&#xff0c;因此我判定是阿里云服務器獨有的問題。如果你的服務器提供商不是阿里云&#xff0c;那么這篇文章可能對你沒有幫助。 如果已經因為升級錯誤導致依賴沖突…

css 點擊后改變樣式

背景&#xff1a; 期望實現效果&#xff1a;鼠標點擊之后&#xff0c;保持選中樣式。 實現思路&#xff1a;在css樣式中&#xff0c;:active 是一種偽類&#xff0c;用于表示用戶當前正在與被選定的元素進行交互。當用戶點擊或按住鼠標時&#xff0c;元素將被激活&#xff0c;此…

采用AI神經網絡降噪算法的語言降噪消回音處理芯片NR2049-P

隨著AI時代來臨.通話設備的環境噪音抑制也進入AI降噪算法時代. AI神經網絡降噪技術是一款革命性的語音處理技術&#xff0c;他突破了傳統單麥克風和雙麥克風降噪的局限性,利用采集的各種日常環境中的噪音樣本進行訓練學習.讓降噪算法具有自適應噪聲抑制功能&#xff0c;可以根…

不用聯網不用編程,PLC通過智能網關快速實現HTTP協議JSON格式與MES等系統平臺雙向數據通訊

智能網關IGT-DSER集成了多種PLC的原廠協議&#xff0c;方便實現各種PLC、智能儀表通過HTTP協議與MES等各種系統平臺通訊對接。PLC內不用編寫程序&#xff0c;設備不用停機&#xff0c;通過網關的參數配置軟件(下載地址)配置JSON文件的字段與PLC寄存器地址等參數即可。 …

如何將兩臺虛擬機進行搭橋

將兩臺虛擬機實現網絡互通&#xff08;“搭橋”&#xff09;需配置虛擬網絡&#xff0c;以下是基于 VMware Workstation 和 VirtualBox 的詳細操作指南&#xff08;以 Windows 系統為例&#xff0c;Linux 原理類似&#xff09;&#xff1a; 一、VMware Workstation 配置&#x…

Xianyu AutoAgent,AI閑魚客服機器人

Xianyu AutoAgent是一款專為閑魚平臺開發的智能客服機器人系統&#xff0c;旨在提供全天候的自動化服務。它具備多專家協同決策、智能議價和上下文感知對話等功能&#xff0c;能夠管理輕量級的對話記憶&#xff0c;利用完整的對話歷史為用戶提供更自然的交流體驗。 Xianyu Aut…

鍵盤輸出希臘字符方法

在不同操作系統中&#xff0c;輸出希臘字母的方法有所不同。以下是針對 Windows 和 macOS 系統的詳細方法&#xff0c;以及一些通用技巧&#xff1a; 1.Windows 系統 1.1 使用字符映射表 字符映射表是一個內置工具&#xff0c;可以方便地找到并插入希臘字母。 ? 步驟&#xf…

什么是SparkONYarn模式

1. 什么是 Spark on YARN&#xff1f; Spark on YARN 是 Apache Spark 的一種部署模式&#xff0c;允許 Spark 應用程序在 Hadoop YARN 集群上運行&#xff0c;充分利用 YARN 的資源管理和調度能力。這種模式將 Spark 與 Hadoop 生態深度集成&#xff0c;使企業能夠在同一集群…

【git】clone項目后續,github clone的網絡配置,大型項目git log 輸出txt,切換commit學習,goland遠程,自存檔

git網絡配置&#xff0c;解決git clone github速度奇慢 git config --global http.proxy http://127.0.0.1:7897 git config --global https.proxy http://127.0.0.1:7897git log輸出到文件&#xff08;便于checkout&#xff09; 這里有些字符如表情會亂碼&#xff0c;不知道…

Java游戲服務器開發流水賬(3)游戲數據的緩存簡介

簡介 游戲服務器數據緩存是一種在游戲服務器運行過程中&#xff0c;用于臨時存儲經常訪問的數據的技術手段&#xff0c;旨在提高游戲性能、降低數據庫負載以及優化玩家體驗。游戲開發中數據的緩存可以使用Java自身的內存也可以使用MemCache&#xff0c;Redis&#xff0c;注意M…

STL?vector!!!

一、前言 之前我們借助手撕string加深了類和對象相關知識&#xff0c;今天我們將一起手撕一個vector&#xff0c;繼續深化類和對象、動態內存管理、模板的相關知識 二、vector相關的前置知識 1、什么是vector&#xff1f; vector是一個STL庫中提供的類模板&#xff0c;它是存儲…

C++學習之路,從0到精通的征途:繼承

目錄 一.繼承的概念及定義 1.繼承的概念 2.繼承的定義 (1)繼承的定義格式 (2)繼承基類成員訪問方式的變化 二.基類與派生類間的轉換 1.派生類對象賦值給基類的引用/指針 2. 派生類對象直接賦值給基類對象 三.繼承的作用域 四.派生類的默認成員函數 1.構造函數 2.拷…

用vue和go實現登錄加密

前端使用CryptoJS默認加密方法&#xff1a; var pass CryptoJS.AES.encrypt(formData.password, key.value).toString()使用 CryptoJS.AES.encrypt() 時不指定加密模式和參數時&#xff0c;CryptoJS 默認會執行以下操作 var encrypted CryptoJS.AES.encrypt("明文&quo…

React百日學習計劃——Deepseek版

階段一&#xff1a;基礎鞏固&#xff08;1-20天&#xff09; 目標&#xff1a;掌握HTML/CSS/JavaScript核心語法和開發環境搭建。 每日學習內容&#xff1a; HTML/CSS&#xff08;1-10天&#xff09; 標簽語義化、盒模型、Flex布局、Grid布局、響應式設計&#xff08;媒體查詢…

WPF中如何自定義控件

WPF自定義控件簡化版&#xff1a;賬戶菜單按鈕&#xff08;AccountButton&#xff09; 我們以**“賬戶菜單按鈕”為例&#xff0c;用更清晰的架構實現一個支持標題顯示、漸變背景、選中狀態高亮**的自定義控件。以下是分步拆解&#xff1a; 一、控件核心功能 我們要做一個類似…

Deepseek+Xmind:秒速生成思維導圖與流程圖

deepseekxmind&#xff0c;快速生成思維導圖和流程圖 文章目錄 思維導圖deepseek筆記本 txt文件xmind 流程圖deepseekdraw.io 思維導圖 deepseek 筆記本 txt文件 將deep seek的東西復制到文本文件中&#xff0c;然后將txt文件拓展名改成md xmind 新建思維導圖----左上角三…