htmlUnit和Selenium的區別以及使用BrowserMobProxy捕獲網絡請求

1. Selenium:瀏覽器自動化之王

核心定位
????????跨平臺、跨語言的瀏覽器操控框架,通過驅動真實瀏覽器實現像素級用戶行為模擬

技術架構

核心特性

  • 支持所有主流瀏覽器(含移動端模擬)

  • 精確的DOM元素定位(XPath/CSS/ID)

  • 屏幕截圖與視頻錄制功能

  • 分布式測試能力(Selenium Grid)

2. HtmlUnit:無頭瀏覽器輕騎兵

核心定位
????????純Java實現的無界面瀏覽器引擎,專為服務端自動化場景優化。

技術架構

核心特性

  • 毫秒級頁面加載速度

  • 線程安全設計

  • 內置基礎AJAX支持

  • Cookie自動管理

3. BrowserMobProxy:網絡流量手術刀

核心定位
基于Netty開發的HTTP代理服務器,專為Web流量監控與操控設計。

技術架構

核心特性

  • 實時流量鏡像

  • 請求/響應內容篡改

  • 性能指標采集(TTFB等)

  • 支持HTTPS中間人攻擊

能力對比矩陣

維度SeleniumHtmlUnitBrowserMobProxy
執行環境真實瀏覽器進程純JVM環境獨立代理服務
JS支持完整ES6+ES5(Rhino引擎)不涉及
網絡延遲模擬需擴展原生支持精確到毫秒級控制
跨域請求處理受同源策略限制自動繞過全流量穿透
移動端調試完整設備模擬僅UA偽裝流量分析
典型應用場景自動化測試服務端爬蟲接口監控

安裝瀏覽器:Google Chrome谷歌為例



4、selenium和BrowserMobProxy捕獲網絡請求實例

驅動下載:Chrome for Testing 的可用性(135后版本)chromedriver.storage.googleapis.com/index.html(舊版本驅動)
安裝需記住安裝位置,啟動時需要設置驅動路徑

代碼實現

getDynamicCrawlersDocument方法為htmlunit的請求監控使用
getParamsByNodeUrl方法為selenium的請求實現,selenium需要驅動支持,可以獲取到復雜的請求接口

依賴:

<dependency><groupId>org.seleniumhq.selenium</groupId><artifactId>selenium-java</artifactId><version>4.10.0</version>
</dependency>
<!-- BrowserMob Proxy -->
<dependency><groupId>net.lightbody.bmp</groupId><artifactId>browsermob-core</artifactId><version>2.1.5</version>
</dependency>
<!-- ChromeDriver -->
<dependency><groupId>org.seleniumhq.selenium</groupId><artifactId>selenium-chrome-driver</artifactId><version>4.1.0</version>
</dependency>

代碼工具類:

package com.zzkj.zei.utils;import com.zzkj.zei.component.ServerConfig;
import lombok.extern.slf4j.Slf4j;
import net.lightbody.bmp.BrowserMobProxy;
import net.lightbody.bmp.BrowserMobProxyServer;
import net.lightbody.bmp.client.ClientUtil;
import net.lightbody.bmp.core.har.Har;
import net.lightbody.bmp.core.har.HarEntry;
import net.lightbody.bmp.core.har.HarRequest;
import net.lightbody.bmp.mitm.manager.ImpersonatingMitmManager;
import net.lightbody.bmp.proxy.CaptureType;
import org.apache.commons.lang3.ObjectUtils;
import org.htmlunit.BrowserVersion;
import org.htmlunit.FailingHttpStatusCodeException;
import org.htmlunit.ScriptException;
import org.htmlunit.WebClient;
import org.htmlunit.html.HtmlPage;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Proxy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.htmlunit.ProxyConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;
import java.time.Duration;
import java.util.*;/*** FileName: SeleniumUtils* Author: wzk* Date:2025/4/29 11:31*/
@Component
@Slf4j
public class SeleniumUtils {private static String SELENIUM_PATH;@Value("${selenium.chromedriver_path}")private String seleniumPath; // 非靜態變量接收注入@PostConstructpublic void init() {SELENIUM_PATH = this.seleniumPath;}private final static List<String> UA_LIST = Arrays.asList("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.0.0 Safari/537.36","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.0.0 Safari/537.36","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.0.0 Safari/537.36","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.0.0 Safari/537.36","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.0.0 Safari/537.36","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.0.0 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.0.0 Safari/537.36");public static void main(String[] args) {
//        List<interfaceNodeData> interfaceNodeDataList = getParamsByNodeUrl(ce,true);List<interfaceNodeData> interfaceNodeDataList = getDynamicCrawlersDocument(gfwj1, 1000, true);for (interfaceNodeData interfaceNodeData : interfaceNodeDataList) {log.info("方法:{}  鏈接:{}   請求參數:{}" ,interfaceNodeData.getMethod(),interfaceNodeData.getUrl(), interfaceNodeData.getParams());}}public static List<interfaceNodeData> getDynamicCrawlersDocument(String url, Integer waitTime, boolean javaScriptEnabled) {List<interfaceNodeData> interfaceNodeDatas = new ArrayList<>();// 1. 啟動BrowserMob代理BrowserMobProxy proxy = new BrowserMobProxyServer();proxy.start(0); // 自動分配端口int proxyPort = proxy.getPort();try {// 2. 配置HtmlUnit使用代理WebClient browser = new WebClient(BrowserVersion.CHROME);browser.getOptions().setProxyConfig(new ProxyConfig("localhost",proxyPort,"http"));// 啟用HTTPS支持(忽略證書驗證)browser.getOptions().setSSLInsecureProtocol("ssl");//解決動態頁面抓取不到信息問題browser.getOptions().setCssEnabled(false);browser.getOptions().setJavaScriptEnabled(javaScriptEnabled);browser.getOptions().setThrowExceptionOnScriptError(false);browser.getOptions().setUseInsecureSSL(true);// 設置自定義的錯誤處理類browser.setJavaScriptErrorListener(new JsoupHtmlUintUtils.MyJSErrorListener());// 開始捕獲請求proxy.newHar("zzjk");HtmlPage page = null;page = browser.getPage(url);// 等待后臺腳本執行時間browser.waitForBackgroundJavaScript(waitTime);//            String pageAsXml = page.asXml();
//            document = Jsoup.parse(pageAsXml.replaceAll("\\<\\?xml.*?\\?>", ""));
//            document.setBaseUri(url);// 5. 獲取并分析HAR數據Har har = proxy.getHar();processHarEntries(har, url, interfaceNodeDatas);} 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());} finally {// 6. 清理資源proxy.stop();}return interfaceNodeDatas;}public static List<interfaceNodeData> getParamsByNodeUrl(String url,Boolean isTime){long stat = new Date().getTime();System.setProperty("webdriver.chrome.driver", SELENIUM_PATH);   //設置chrome驅動程序的路徑BrowserMobProxy proxy = new BrowserMobProxyServer();proxy.start(0); // 自動選擇端口// 獲取Selenium的Proxy對象Proxy seleniumProxy = ClientUtil.createSeleniumProxy(proxy);ChromeOptions opt = new ChromeOptions();opt.addArguments();opt.addArguments("--headless",               // 開啟無界面模式"--disable-gpu",            // 禁用gpu"--remote-allow-origins=*", // 允許所有源訪問"--ignore-certificate-errors", // 忽略證書錯誤"--user-agent=" + UA_LIST.get(0), // 設置請求頭"--no-sandbox",             // 禁用沙盒,減少權限檢查"--disable-dev-shm-usage",  // 避免共享內存問題"--log-level=3",            // 禁用 Chrome 日志"--blink-settings=imagesEnabled=false", // 禁止圖片加載"--disable-extensions",     // 禁用擴展"--disable-javascript",     // 禁用 JavaScript(如果目標頁面不需要 JS)"--disable-css",            // 禁用 CSS 渲染(按需)"--disable-fonts",          // 禁用字體加載"--dns-prefetch-disable",    // 禁用 DNS 預解析"--disk-cache-size=0",       // 禁用 緩存"--disable-cache"            // 禁用 緩存);opt.setCapability(CapabilityType.PROXY, seleniumProxy);WebDriver driver = new ChromeDriver(opt);   //初始化一個chrome驅動實例,保存到driver中try {driver.manage().window().maximize();driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); // 啟用隱式等待return seleniumGetDocument(driver,proxy,url,isTime);} catch (Exception e) {log.info("錯誤URL: " + driver.getCurrentUrl());e.printStackTrace();} finally {driver.quit();  // 自動清理Cookies和會話proxy.stop();long end = new Date().getTime();log.info("selenium參數獲取時間" + (end - stat));}return null;}public static List<interfaceNodeData> seleniumGetDocument(WebDriver driver, BrowserMobProxy proxy, String url,Boolean isTime) {List<interfaceNodeData> dataList = new ArrayList<>();try {// 啟用MITM抓取HTTPSproxy.setMitmManager(new ImpersonatingMitmManager.Builder().trustAllServers(true).build());proxy.setHarCaptureTypes(CaptureType.REQUEST_CONTENT, CaptureType.RESPONSE_CONTENT);proxy.newHar("zzkj");// 訪問頁面并等待driver.get(url);// 等待頁面加載完成new WebDriverWait(driver, Duration.ofSeconds(30)).until(webDriver -> ((JavascriptExecutor) webDriver).executeScript("return document.readyState").equals("complete"));// 驗證請求是否穩定validationAll(proxy);if (isTime){Thread.sleep(10000); // 休眠10秒}// 處理HAR數據Har har = proxy.getHar();processHarEntries(har, url, dataList);} catch (Exception e) {e.printStackTrace();}return dataList;}private static void validationAll(BrowserMobProxy proxy) throws InterruptedException {int retries = 0;int stableCount = 0;int lastEntrySize = 0;while (retries < 30 && stableCount < 3) { // 最多等30秒,穩定3次Thread.sleep(1000); // 每秒檢查一次int currentSize = proxy.getHar().getLog().getEntries().size();if (currentSize == lastEntrySize) {stableCount++;} else {stableCount = 0;lastEntrySize = currentSize;}retries++;}if (retries >= 30) {log.info("----------------------- 請求驗證穩定超時 -----------------------");}}// 處理 HAR 條目并過濾private static void processHarEntries(Har har, String baseUrl, List<interfaceNodeData> interfaceNodeDatas) {har.getLog().getEntries().forEach(entry -> {HarRequest request = entry.getRequest();String method = request.getMethod();String toUrl = request.getUrl();log.info("檢測鏈接:{}",toUrl);// 過濾boolean isStaticResource = toUrl.matches(".*\\.(css|js|png|jpg|jpeg|gif|ico|woff|woff2|svg|mp4|mp3)(\\?.*)?$");boolean isStaticPath = toUrl.contains("/material/") ||toUrl.contains("/fonts/") ||toUrl.contains("/script/") ||toUrl.contains("/login/") ||toUrl.contains("/images/");if (("POST".equalsIgnoreCase(method) || "GET".equalsIgnoreCase(method)) &&
//                    !filterOutsideUrl(baseUrl, toUrl) &&isCurrentNodeUrl(baseUrl,toUrl) &&!isStaticResource &&!isStaticPath) {interfaceNodeData interfaceNodeData = new interfaceNodeData();interfaceNodeData.setUrl(toUrl);interfaceNodeData.setMethod(method);interfaceNodeData.setData(entry.getResponse().getContent().getText());interfaceNodeData.setParams(ObjectUtils.isEmpty(request.getPostData()) ? "" : request.getPostData().getText());interfaceNodeDatas.add(interfaceNodeData);}});}private static boolean isCurrentNodeUrl(String sourceUrl, String targetUrl) {// 移除協議、轉為小寫、處理末尾斜杠和index.htmlString normalizedSource = normalizeUrl(sourceUrl);String normalizedTarget = normalizeUrl(targetUrl);// 判斷目標URL是否以當前節點URL開頭return !normalizedSource.contains(normalizedTarget);}/*** 標準化URL處理*/private static String normalizeUrl(String url) {// 移除協議頭并轉為小寫String normalized = url.replaceAll("^(http://|https://)", "").toLowerCase();// 移除末尾的 "/" 和 "index.html"normalized = normalized.replaceAll("/+$", "").replaceAll("/index\\.html$", "");return normalized;}}
package com.zzkj.zei.utils;import lombok.Data;/*** FileName: interfaceNodeData* Author: wzk* Date:2025/4/30 17:00*/
@Data
public class interfaceNodeData {String url;String data;String method;String params;interfaceNodeData(){}interfaceNodeData(String url,String method,String data,String params){this.url = url;this.method = method;this.data = data;this.params = params;}
}


?

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

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

相關文章

SSRF相關

SSRF(Server Side Request Forgery,服務器端請求偽造)&#xff0c;攻擊者以服務器的身份發送一條構造好的請求給服務器所在地內網進行探測或攻擊。 產生原理&#xff1a; 服務器端提供了能從其他服務器應用獲取數據的功能&#xff0c;如從指定url獲取網頁內容、加載指定地址的圖…

SaaS備份的必要性:廠商之外的數據保護策略

在當今數字化時代&#xff0c;企業對SaaS&#xff08;軟件即服務&#xff09;應用的依賴程度不斷攀升。SaaS應用為企業提供了便捷的生產力工具&#xff0c;然而&#xff0c;這也使得數據安全面臨諸多挑戰&#xff0c;如意外刪除、勒索軟件攻擊以及供應商故障等。因此&#xff0…

【Python 基礎語法】

Python 基礎語法是編程的基石&#xff0c;以下從核心要素到實用技巧進行系統梳理&#xff1a; 一、代碼結構規范 縮進規則 使用4個空格縮進&#xff08;PEP 8標準&#xff09;縮進定義代碼塊&#xff08;如函數、循環、條件語句&#xff09; def greet(name):if name: # 正確縮…

利用“Flower”實現聯邦機器學習的實戰指南

一個很尷尬的現狀就是我們用于訓練 AI 模型的數據快要用完了。所以我們在大量的使用合成數據&#xff01; 據估計&#xff0c;目前公開可用的高質量訓練標記大約有 40 萬億到 90 萬億個&#xff0c;其中流行的 FineWeb 數據集包含 15 萬億個標記&#xff0c;僅限于英語。 作為…

自動化測試與功能測試詳解

&#x1f345; 點擊文末小卡片&#xff0c;免費獲取軟件測試全套資料&#xff0c;資料在手&#xff0c;漲薪更快 什么是自動化測試? 自動化測試是指利用軟件測試工具自動實現全部或部分測試&#xff0c;它是軟件測試的一個重要組成 部分&#xff0c;能完成許多手工測試無…

MySQL全量,增量備份與恢復

目錄 一.MySQL數據庫備份概述 1.數據備份的重要性 2.數據庫備份類型 3.常見的備份方法 二&#xff1a;數據庫完全備份操作 1.物理冷備份與恢復 2.mysqldump 備份與恢復 3.MySQL增量備份與恢復 3.1MySQL增量恢復 3.2MySQL備份案例 三&#xff1a;定制企業備份策略思路…

Ubuntu 安裝 Nginx

Nginx 是一個高性能的 Web 服務器和反向代理服務器&#xff0c;同時也可以用作負載均衡器和 HTTP 緩存。 Nginx 的主要用途 用途說明Web服務器提供網頁服務&#xff0c;處理用戶的 HTTP 請求&#xff0c;返回 HTML、CSS、JS、圖片等靜態資源。反向代理服務器將用戶請求轉發到…

人工智能 機器學習期末考試題

自測試卷2 一、選擇題 1&#xff0e;下面哪個屬性不是NumPy中數組的屬性&#xff08; &#xff09;。 A&#xff0e;ndim B&#xff0e;size C&#xff0e;shape D&#xff0e;add 2&#xff0e;一個簡單的Series是由&#xff08; &#xff09;的數據組成的。 A&#xff0e;兩…

使用阿里云CLI調用OpenAPI

介紹使用阿里云CLI調用OpenAPI的具體操作流程&#xff0c;包括安裝、配置憑證、生成并調用命令等步驟。 方案概覽 使用阿里云CLI調用OpenAPI&#xff0c;大致分為四個步驟&#xff1a; 安裝阿里云CLI&#xff1a;根據您使用設備的操作系統&#xff0c;選擇并安裝相應的版本。…

K8S Svc Port-forward 訪問方式

在 Kubernetes 中&#xff0c;kubectl port-forward 是一種 本地與集群內資源&#xff08;Pod/Service&#xff09;建立臨時網絡隧道 的訪問方式&#xff0c;無需暴露服務到公網&#xff0c;適合開發調試、臨時訪問等場景。以下是詳細使用方法及注意事項&#xff1a; 1. 基礎用…

23、DeepSeek-V2論文筆記

DeepSeek-V2 1、背景2、KV緩存優化2.0 KV緩存&#xff08;Cache&#xff09;的核心原理2.1 KV緩存優化2.2 性能對比2.3 架構2.4多頭注意力 &#xff08;MHA&#xff09;2.5 多頭潛在注意力 &#xff08;MLA&#xff09;2.5.1 低秩鍵值聯合壓縮 &#xff08;Low-Rank Key-Value …

MySQL OCP試題解析(2)

試題如下圖所示&#xff1a; 一、題目背景還原 假設存在以下MySQL用戶權限配置&#xff1a; -- 創建本地會計用戶CREATE USER accountinglocalhost IDENTIFIED BY acc_123;-- 創建匿名代理用戶&#xff08;用戶名為空&#xff0c;允許任意主機&#xff09;CREATE USER % IDENTI…

深度學習Y7周:YOLOv8訓練自己數據集

&#x1f368; 本文為&#x1f517;365天深度學習訓練營中的學習記錄博客&#x1f356; 原作者&#xff1a;K同學啊 一、配置環境 1.官網下載源碼 2.安裝需要環境 二、準備好自己的數據 目錄結構&#xff1a; 主目錄 data images&#xff08;存放圖片&#xff09; annotati…

英偉達Blackwell架構重構未來:AI算力革命背后的技術邏輯與產業變革

——從芯片暴力美學到分布式智能體網絡&#xff0c;解析英偉達如何定義AI基礎設施新范式 開篇&#xff1a;當算力成為“新石油”&#xff0c;英偉達的“煉油廠”如何升級&#xff1f; 2025年3月&#xff0c;英偉達GTC大會上&#xff0c;黃仁勛身披標志性皮衣&#xff0c;宣布了…

CurrentHashMap的整體系統介紹及Java內存模型(JVM)介紹

當我們提到ConurrentHashMap時&#xff0c;先想到的就是HashMap不是線程安全的&#xff1a; 在多個線程共同操作HashMap時&#xff0c;會出現一個數據不一致的問題。 ConcurrentHashMap是HashMap的線程安全版本。 它通過在相應的方法上加鎖&#xff0c;來保證多線程情況下的…

Android開發-設計規范

在Android應用開發中&#xff0c;遵循良好的設計規范不僅能夠提升用戶體驗&#xff0c;還能確保代碼的可維護性和擴展性。本文將從用戶界面&#xff08;UI&#xff09;、用戶體驗&#xff08;UX&#xff09;、性能優化以及代碼結構等多個維度探討Android開發中的設計規范&#…

泛型加持的策略模式:打造高擴展的通用策略工具類

一、傳統策略模式的痛點與突破 1.1 傳統策略實現回顧 // 傳統支付策略接口 public interface PaymentStrategy {void pay(BigDecimal amount); }// 具體策略實現 public class AlipayStrategy implements PaymentStrategy {public void pay(BigDecimal amount) { /* 支付寶支…

物聯網從HomeAssistant開始

文章目錄 一、什么是home-assistant?1.核心架構2.集成架構 二、在樹梅派5上安裝home-assistant三、接入米家1.對比下趨勢2.手動安裝插件3.配置方式 四、接入公牛1.手動安裝插件2.配置方式 五、接入海爾1.手動安裝插件2.配置方式 六、接入國家電網 一、什么是home-assistant? …

系統架構-嵌入式系統架構

原理與特征 嵌入式系統的典型架構可概括為兩種模式&#xff0c;即層次化模式架構和遞歸模式架構 層次化模式架構&#xff0c;位于高層的抽象概念與低層的更加具體的概念之間存在著依賴關系&#xff0c;封閉型層次架構指的是&#xff0c;高層的對象只能調用同一層或下一層對象…

計算機圖形學編程(使用OpenGL和C++)(第2版)學習筆記 09.天空和背景

天空和背景 對于 3D 場景&#xff0c;通常可以通過在遠處的地平線附近創造一些逼真的效果&#xff0c;來增強其真實感。我們可以采用天空盒、天空柱&#xff08;Skydome&#xff09;或天空穹&#xff08;Skydome&#xff09;等技術來模擬天空。 天空盒 天空盒&#xff08;Sk…