Java+Selenium+快代理實現高效爬蟲

目錄

  • 一、前言
  • 二、Selenium簡介
  • 三、環境準備
  • 四、代碼實現
    • 4.1 創建WebDriver工廠類
    • 4.2 創建爬蟲主類
    • 4.3 配置代理的注意事項
  • 六、總結與展望

一、前言

在Web爬蟲技術中,Selenium作為一款強大的瀏覽器自動化工具,能夠模擬真實用戶操作,有效應對JavaScript渲染、Ajax加載等復雜場景。而集成代理服務則能夠解決IP限制、地域訪問限制等問題。本文將詳細介紹如何利用Java+Selenium+快代理實現高效的爬蟲系統。

二、Selenium簡介

Selenium是一個用于Web應用程序自動化測試的工具集,它主要用于自動化瀏覽器操作,可以模擬用戶與網頁的交互行為,如點擊按鈕、填寫表單、滾動頁面等。在爬蟲領域,Selenium特別適合處理那些需要JavaScript渲染、需要登錄或有反爬措施的網站。

三、環境準備

  • JDK1.8
  • Maven項目管理
  • 相關依賴
<!-- Selenium -->
<dependency><groupId>org.seleniumhq.selenium</groupId><artifactId>selenium-java</artifactId><version>3.141.59</version>
</dependency>
<dependency><groupId>io.github.bonigarcia</groupId><artifactId>webdrivermanager</artifactId><version>5.3.2</version>
</dependency>

四、代碼實現

本系統采用的是工廠模式創建WebDriver實例,這樣做的好處主要是可以提供統一的創建方法,不管使用那種瀏覽器都適用,自由配置。其次就是維護方便,瀏覽器配置變更只需修改工廠類中的相關方法,擴展性也不錯,可以輕松添加新的瀏覽器支持,比如Opera或者Safari等等。

4.1 創建WebDriver工廠類

import io.github.bonigarcia.wdm.WebDriverManager;
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.edge.EdgeDriver;
import org.openqa.selenium.edge.EdgeOptions;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.PageLoadStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;/*** WebDriver工廠類,負責創建和配置各種瀏覽器驅動實例* 設計思路:* 1. 使用工廠模式統一管理不同瀏覽器的WebDriver創建邏輯* 2. 采用構建器模式(Builder Pattern)使配置更加靈活* 3. 封裝復雜的瀏覽器選項設置,簡化調用代碼* 4. 支持多種瀏覽器類型和代理配置* * 好處:* 1. 代碼復用性高,減少重復代碼* 2. 配置靈活,通過鏈式調用設置參數* 3. 職責單一,僅負責創建WebDriver* 4. 易于擴展,可輕松添加新的瀏覽器類型支持*/
public class WebDriverFactory {// 使用SLF4J記錄日志,便于問題排查private static final Logger log = LoggerFactory.getLogger(WebDriverFactory.class);// 默認配置,可通過構建器方法修改private boolean headless = true;                // 默認無頭模式private int pageLoadTimeoutSeconds = 30;        // 頁面加載超時時間private int scriptTimeoutSeconds = 30;          // 腳本執行超時時間private int implicitWaitSeconds = 10;           // 隱式等待時間// 代理配置private boolean proxyEnabled = false;           // 是否啟用代理private String proxyHost;                       // 代理主機地址private int proxyPort;                          // 代理端口private String proxyUsername;                   // 代理用戶名(認證用)private String proxyPassword;                   // 代理密碼(認證用)/*** 支持的瀏覽器類型枚舉* 便于擴展,后續可以增加其他瀏覽器支持*/public enum BrowserType {CHROME, EDGE, FIREFOX}/*** 設置是否使用無頭模式* 無頭模式下瀏覽器不會顯示界面,更加節省資源* * @param headless true表示使用無頭模式,false表示顯示瀏覽器界面* @return 當前工廠實例,支持鏈式調用*/public WebDriverFactory withHeadless(boolean headless) {this.headless = headless;return this;}/*** 設置頁面加載超時時間* * @param seconds 超時秒數* @return 當前工廠實例,支持鏈式調用*/public WebDriverFactory withPageLoadTimeout(int seconds) {this.pageLoadTimeoutSeconds = seconds;return this;}/*** 設置JavaScript腳本執行超時時間* * @param seconds 超時秒數* @return 當前工廠實例,支持鏈式調用*/public WebDriverFactory withScriptTimeout(int seconds) {this.scriptTimeoutSeconds = seconds;return this;}/*** 設置元素查找隱式等待時間* * @param seconds 等待秒數* @return 當前工廠實例,支持鏈式調用*/public WebDriverFactory withImplicitWait(int seconds) {this.implicitWaitSeconds = seconds;return this;}/*** 配置代理服務器* * @param host 代理主機地址* @param port 代理端口* @return 當前工廠實例,支持鏈式調用*/public WebDriverFactory withProxy(String host, int port) {this.proxyEnabled = true;this.proxyHost = host;this.proxyPort = port;return this;}/*** 配置代理服務器認證信息* * @param username 代理用戶名* @param password 代理密碼* @return 當前工廠實例,支持鏈式調用*/public WebDriverFactory withProxyAuth(String username, String password) {this.proxyUsername = username;this.proxyPassword = password;return this;}/*** 創建指定類型的WebDriver實例* 工廠方法核心,根據指定的瀏覽器類型創建對應的WebDriver* * @param browserType 瀏覽器類型枚舉* @return 配置好的WebDriver實例*/public WebDriver createWebDriver(BrowserType browserType) {switch (browserType) {case CHROME:return createChromeDriver();case EDGE:return createEdgeDriver();case FIREFOX:return createFirefoxDriver();default:// 默認使用Edge瀏覽器log.info("未指定瀏覽器類型,默認使用Edge瀏覽器");return createEdgeDriver();}}/*** 創建Edge瀏覽器WebDriver實例* * @return 配置好的Edge WebDriver*/private WebDriver createEdgeDriver() {// 自動下載與系統瀏覽器匹配的WebDriver,避免版本不匹配問題WebDriverManager.edgedriver().setup();EdgeOptions options = new EdgeOptions();// 配置瀏覽器選項Map<String, Object> edgePrefs = new HashMap<>();// 禁用自動擴展,減少資源占用和干擾edgePrefs.put("useAutomationExtension", false);// 獲取通用瀏覽器參數List<String> args = getCommonBrowserArgs();Map<String, Object> edgeOptions = new HashMap<>();edgeOptions.put("args", args);// 設置User-Agent,模擬真實瀏覽器,減少被網站識別為爬蟲的可能options.setCapability("ms.edge.userAgent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0");// 設置頁面加載策略為NORMAL,確保頁面完整加載// 可選值:NONE (不等待加載), EAGER (DOM就緒即可), NORMAL (等待完全加載)options.setPageLoadStrategy(PageLoadStrategy.NORMAL);// Edge特有配置options.setCapability("ms:edgeChromium", true);options.setCapability("ms:edgeOptions", edgeOptions);// 使用隱私模式,避免歷史記錄、cookie等信息的干擾options.setCapability("inPrivate", true);// 配置代理configureProxy(options);// 創建WebDriver實例WebDriver driver = new EdgeDriver(options);// 配置超時設置configureTimeouts(driver);log.info("Edge WebDriver創建成功");return driver;}/*** 創建Chrome瀏覽器WebDriver實例* * @return 配置好的Chrome WebDriver*/private WebDriver createChromeDriver() {// 自動下載與系統瀏覽器匹配的WebDriverWebDriverManager.chromedriver().setup();ChromeOptions options = new ChromeOptions();// 根據配置決定是否使用無頭模式if (headless) {options.addArguments("--headless");}// 添加通用瀏覽器參數for (String arg : getCommonBrowserArgs()) {options.addArguments(arg);}// 設置頁面加載策略options.setPageLoadStrategy(PageLoadStrategy.NORMAL);// Chrome瀏覽器特殊處理代理配置configureProxyForChrome(options);// 創建WebDriver實例WebDriver driver = new ChromeDriver(options);// 配置超時設置configureTimeouts(driver);log.info("Chrome WebDriver創建成功");return driver;}/*** 創建Firefox瀏覽器WebDriver實例* * @return 配置好的Firefox WebDriver*/private WebDriver createFirefoxDriver() {// 自動下載與系統瀏覽器匹配的WebDriverWebDriverManager.firefoxdriver().setup();FirefoxOptions options = new FirefoxOptions();// 根據配置決定是否使用無頭模式if (headless) {options.addArguments("--headless");}// 配置代理configureProxy(options);// 創建WebDriver實例WebDriver driver = new FirefoxDriver(options);// 配置超時設置configureTimeouts(driver);log.info("Firefox WebDriver創建成功");return driver;}/*** 獲取通用瀏覽器啟動參數* 這些參數適用于基于Chromium的瀏覽器(Chrome, Edge)* * @return 參數列表*/private List<String> getCommonBrowserArgs() {List<String> args = new ArrayList<>();// 無頭模式相關參數if (headless) {args.add("--headless");  // 不顯示瀏覽器界面args.add("--disable-gpu");  // 在某些系統上無頭模式需要禁用GPU加速}// 禁用擴展和插件,減少資源占用和干擾args.add("--disable-extensions");// 禁用圖片加載,提高性能args.add("--blink-settings=imagesEnabled=false");// 解決在Docker容器中可能出現的共享內存問題args.add("--disable-dev-shm-usage");// 禁用平滑滾動,減少自動滾動問題args.add("--disable-smooth-scrolling");// 設置固定窗口大小,避免響應式變化導致的元素定位問題args.add("--window-size=1366,768");// 禁用站點隔離,減少內存使用args.add("--disable-features=site-per-process");// 禁用默認應用,減少啟動時間args.add("--disable-default-apps");// 減少日志輸出,提高性能args.add("--disable-logging");// 禁用信息欄,避免干擾args.add("--disable-infobars");// 禁用通知,避免干擾args.add("--disable-notifications");// 添加性能優化參數args.add("--disable-web-security");  // 禁用同源策略檢查args.add("--no-sandbox");  // 禁用沙箱模式,提高性能(注意安全風險)args.add("--disable-setuid-sandbox");  // 禁用setuid沙箱,配合--no-sandbox使用args.add("--disable-accelerated-2d-canvas");  // 禁用加速2D Canvas,減少GPU使用args.add("--disable-crash-reporter");  // 禁用崩潰報告args.add("--disable-in-process-stack-traces");  // 禁用進程內堆棧跟蹤args.add("--disable-breakpad");  // 禁用斷點調試args.add("--aggressive-cache-discard");  // 積極丟棄緩存,減少內存使用args.add("--disable-ipc-flooding-protection");  // 禁用IPC洪水保護// 限制JavaScript引擎內存使用,防止內存溢出args.add("--js-flags=--max-old-space-size=512");return args;}/*** 為瀏覽器選項配置代理* 適用于Edge和Firefox瀏覽器* * @param options 瀏覽器選項對象*/private void configureProxy(Object options) {if (proxyEnabled && proxyHost != null && !proxyHost.isEmpty() && proxyPort > 0) {try {// 構建代理URL,處理是否需要認證String proxyUrl;if (proxyUsername != null && !proxyUsername.isEmpty() && proxyPassword != null) {// 帶認證的代理格式:http://username:password@host:portproxyUrl = "http://" + proxyUsername + ":" + proxyPassword + "@" + proxyHost + ":" + proxyPort;} else {// 不帶認證的代理格式:http://host:portproxyUrl = "http://" + proxyHost + ":" + proxyPort;}// 創建代理對象Proxy proxy = new Proxy();// 同時設置HTTP和HTTPS代理,確保所有請求都通過代理proxy.setHttpProxy(proxyUrl);proxy.setSslProxy(proxyUrl);// 根據瀏覽器類型設置代理能力if (options instanceof EdgeOptions) {((EdgeOptions) options).setCapability(CapabilityType.PROXY, proxy);} else if (options instanceof FirefoxOptions) {((FirefoxOptions) options).setCapability(CapabilityType.PROXY, proxy);}log.info("WebDriver配置了代理: {}", proxyHost + ":" + proxyPort);} catch (Exception e) {log.error("配置代理時出錯: {}", e.getMessage());}}}/*** 為Chrome瀏覽器特別配置代理* Chrome處理代理的方式與Edge和Firefox略有不同* * @param options Chrome瀏覽器選項對象*/private void configureProxyForChrome(ChromeOptions options) {if (proxyEnabled && proxyHost != null && !proxyHost.isEmpty() && proxyPort > 0) {try {// 構建代理URL,處理是否需要認證String proxyUrl;if (proxyUsername != null && !proxyUsername.isEmpty() && proxyPassword != null) {// 帶認證的代理proxyUrl = "http://" + proxyUsername + ":" + proxyPassword + "@" + proxyHost + ":" + proxyPort;} else {// 不帶認證的代理proxyUrl = "http://" + proxyHost + ":" + proxyPort;}// 創建代理對象Proxy proxy = new Proxy();proxy.setHttpProxy(proxyUrl);proxy.setSslProxy(proxyUrl);// 為Chrome設置代理能力options.setCapability(CapabilityType.PROXY, proxy);log.info("Chrome WebDriver配置了代理: {}", proxyHost + ":" + proxyPort);} catch (Exception e) {log.error("配置Chrome代理時出錯: {}", e.getMessage());}}}/*** 配置WebDriver的各種超時設置* * @param driver WebDriver實例*/private void configureTimeouts(WebDriver driver) {// 設置頁面加載超時時間driver.manage().timeouts().pageLoadTimeout(pageLoadTimeoutSeconds, TimeUnit.SECONDS);// 設置腳本執行超時時間driver.manage().timeouts().setScriptTimeout(scriptTimeoutSeconds, TimeUnit.SECONDS);// 設置隱式等待時間,查找元素時使用driver.manage().timeouts().implicitlyWait(implicitWaitSeconds, TimeUnit.SECONDS);log.debug("WebDriver超時配置完成:頁面加載={}秒,腳本執行={}秒,隱式等待={}秒",pageLoadTimeoutSeconds, scriptTimeoutSeconds, implicitWaitSeconds);}
}

4.2 創建爬蟲主類

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.List;/*** Selenium爬蟲示例主類* 演示如何使用WebDriverFactory創建瀏覽器實例并進行網頁爬取*/
public class SeleniumCrawler {private static final Logger log = LoggerFactory.getLogger(SeleniumCrawler.class);public static void main(String[] args) {// 推薦使用快代理的隧道代理:https://www.kuaidaili.com/?ref=soi1rkc6rd82String proxyHost = "";  // 快代理隧道代理主機int proxyPort = 15818;                // 端口,根據實際情況修改String proxyUsername = "yourUsername"; // 替換為您的快代理用戶名String proxyPassword = "yourPassword"; // 替換為您的快代理密碼// 創建WebDriver工廠實例,配置爬蟲參數// 使用構建器模式,代碼可讀性強,配置靈活WebDriverFactory factory = new WebDriverFactory().withHeadless(false)  // 設置為false可以看到瀏覽器界面,方便調試.withPageLoadTimeout(30)  // 頁面加載超時設置為30秒.withScriptTimeout(30)    // 腳本執行超時設置為30秒  .withImplicitWait(10)     // 查找元素隱式等待10秒.withProxy(proxyHost, proxyPort)           // 設置快代理的主機和端口.withProxyAuth(proxyUsername, proxyPassword);  // 設置代理認證信息WebDriver driver = null;try {// 創建Edge瀏覽器實例,也可以選擇Chrome或Firefoxlog.info("正在初始化WebDriver...");driver = factory.createWebDriver(WebDriverFactory.BrowserType.EDGE);// 開始爬蟲任務crawlWebsite(driver);} catch (Exception e) {// 異常處理,記錄詳細錯誤信息便于排錯log.error("爬蟲執行出錯: {}", e.getMessage(), e);} finally {// 確保WebDriver正確關閉,避免資源泄露if (driver != null) {driver.quit();log.info("WebDriver已關閉,爬蟲任務結束");}}}/*** 爬蟲核心邏輯,可根據實際需求擴展* * @param driver 已配置好的WebDriver實例* @throws InterruptedException 如果線程休眠被中斷*/private static void crawlWebsite(WebDriver driver) throws InterruptedException {// 訪問目標網站log.info("開始訪問目標網站");driver.get("https://www.baidu.com");log.info("網頁標題: {}", driver.getTitle());// 顯式等待某個元素出現,確保頁面加載完成// 比簡單的Thread.sleep更智能WebDriverWait wait = new WebDriverWait(driver, 10);wait.until(ExpectedConditions.presenceOfElementLocated(By.tagName("body")));// 獲取頁面內容示例:提取所有鏈接log.info("開始提取頁面鏈接");List<WebElement> links = driver.findElements(By.tagName("a"));log.info("共發現{}個鏈接", links.size());// 處理提取到的鏈接for (WebElement link : links) {String text = link.getText().trim();String href = link.getAttribute("href");// 只記錄有效鏈接if (href != null && !href.isEmpty()) {log.info("鏈接: {} -> {}", text.isEmpty() ? "[無文本]" : text, href);}}// 模擬更多爬蟲操作,例如點擊某個元素、填寫表單等// 這里作為示例,只是簡單等待log.info("等待頁面進一步處理...");Thread.sleep(2000);// 如果需要,可以繼續訪問更多頁面// driver.get("https://www.another-site.com");// ...log.info("爬蟲任務完成");}
}

4.3 配置代理的注意事項

在使用代理時,需要注意以下幾點:

  1. 選擇合適的代理類型:隧道代理適合大規模爬蟲,普通代理適合小規模測試
  2. 正確配置認證信息:確保用戶名和密碼正確,特殊字符需要URL編碼
  3. 測試代理連通性:使用前先測試代理是否可用
  4. 合理設置請求頻率:遵循代理服務商的使用建議,避免觸發反爬機制
  5. 注意IP切換時機:適時切換IP,避免同一IP頻繁訪問目標網站

六、總結與展望

本文詳細介紹了如何使用Java+Selenium+快代理實現高效的網頁爬蟲。通過工廠模式和構建器模式的應用,我們實現了一個靈活、可擴展且易于使用的爬蟲框架。該框架解決了代理認證配置的難題,優化了瀏覽器參數設置,提高了爬蟲的穩定性和效率。

Selenium與代理服務的結合為我們提供了強大的爬蟲能力:Selenium模擬真實用戶行為應對JavaScript渲染和復雜交互,而快代理則提供了穩定的IP資源池,有效規避IP封禁和地域限制問題。這種組合特別適合需要處理登錄驗證、動態加載內容或有反爬措施的網站。

在實際應用中,請務必遵守相關法律法規和網站的使用條款,合理設置爬蟲的請求頻率和數量,避免對目標網站造成不必要的負擔。同時,定期更新Selenium和WebDriver版本,以適應瀏覽器的更新和網站的變化。

如果你在使用過程中遇到問題,可以參考快代理或查閱Selenium的相關資料。希望本文對你的爬蟲開發有所幫助!

最后,隨著網站反爬技術的不斷進化,爬蟲技術也需要持續更新迭代。未來,我們可以考慮結合機器學習技術識別驗證碼,或通過更智能的策略調整爬取行為,使爬蟲更加智能和高效。

歡迎在評論區分享你的使用經驗和改進建議!


推薦閱讀:

  • Selenium官方文檔
  • WebDriverManager使用指南
  • 快代理API文檔
  • 爬蟲法律法規與道德規范

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

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

相關文章

SpringBoot配置文件的合并

需求:想分類將mysql數據庫的配置放在一個文件,redis的配置放在另外一個文件 就不去引入mysql和redis了,看能否得到值就行了 測試結果 model的包放錯了 應該移動到demo里 能否用yml或者yaml呢 這里注意yml的寫法 測試結果也是可以的 注意如果主配置文件是yml或者yaml的話

深入理解 BFC:網頁布局的關鍵機制

在前端開發的世界里&#xff0c;網頁布局是一項至關重要的任務。而在眾多布局相關的概念中&#xff0c;BFC&#xff08;Block Formatting Context&#xff0c;塊級格式化上下文&#xff09;扮演著極為關鍵的角色。今天&#xff0c;就讓我們深入剖析 BFC 的方方面面。 一、BFC …

04-Web后端基礎(基礎知識)

而像HTML、CSS、JS 以及圖片、音頻、視頻等這些資源&#xff0c;我們都稱為靜態資源。 所謂靜態資源&#xff0c;就是指在服務器上存儲的不會改變的數據&#xff0c;通常不會根據用戶的請求而變化。 那與靜態資源對應的還有一類資源&#xff0c;就是動態資源。那所謂動態資源&…

Vue3 Element Plus el-table-column Sortable 排序失效

問題描述&#xff1a; vue3中 element plus 中 el-table 的 el-table-column使用了插槽后&#xff0c;為什么sortable不起效果&#xff0c;不能點擊排序 <el-table-columnlabel"記賬日期"width"110"fixed"left"header-align"left"…

Unity中SRP Batcher使用整理

SRP Batcher 是一種繪制調用優化,可顯著提高使用 SRP 的應用程序的性能,SRP Batcher 減少了Unity為使用相同著色器變體的材質準備和調度繪制調用所需的CPU 時間。 工作原理: 傳統優化方法通過減少繪制調用次數提升性能,而SRP Batcher的核心理念在于降低繪制調用間的渲染狀…

服務器的基礎知識

什么是服務器 配置牛、運行穩、價格感人的高級計算機&#xff0c;家用電腦不能比擬的。 服務器的組成&#xff1a;電源、raid卡、網卡、內存、cpu、主板、風扇、硬盤。 服務器的分類 按計算能力分類 超級計算機 小型機AIX x86服務器&#xff08;服務器cpu架構&#xff09; …

服務器網絡配置 netplan一個網口配置兩個ip(雙ip、輔助ip、別名IP別名)

文章目錄 問答 問 # This is the network config written by subiquity network:ethernets:enp125s0f0:dhcp4: noaddresses: [192.168.90.180/24]gateway4: 192.168.90.1nameservers:addresses:- 172.0.0.207- 172.0.0.208enp125s0f1:dhcp4: trueenp125s0f2:dhcp4: trueenp125…

高級SQL技巧:時序數據查詢優化與性能調優實戰

高級SQL技巧&#xff1a;時序數據查詢優化與性能調優實戰 引言 在現代數據驅動型系統中&#xff0c;時序數據&#xff08;時間序列數據&#xff09;正成為企業核心資產之一。然而&#xff0c;隨著數據量激增和復雜業務需求的不斷涌現&#xff0c;傳統的SQL查詢方式已難以滿足…

DDoS攻擊應對指南:提升網站安全性的有效策略

DDoS&#xff08;分布式拒絕服務&#xff09;攻擊成為了企業面臨的主要網絡安全威脅之一。隨著技術的不斷發展&#xff0c;DDoS攻擊手段也在不斷升級&#xff0c;給企業的網絡安全帶來了極大的挑戰。針對這一問題&#xff0c;企業需要采取有效的防御措施&#xff0c;以保障網站…

Appium 的 enableMultiWindows 參數

引言 在移動應用自動化測試中&#xff0c;??混合應用&#xff08;Hybrid App&#xff09;?? 和多窗口場景&#xff08;如分屏、彈窗、多 WebView&#xff09;的處理一直是技術難點。Appium 的 enableMultiWindows 參數為這類場景提供了關鍵支持&#xff0c;但在實際使用中常…

C++中的菱形繼承問題

假設有一個問題&#xff0c;類似于鴨子這樣的動物有很多種&#xff0c;如企鵝和魷魚&#xff0c;它們也可能會有一些共同的特性。例如&#xff0c;我們可以有一個叫做 AquaticBird &#xff08;涉禽&#xff0c;水鳥的一類&#xff09;的類&#xff0c;它又繼承自 Animal 和 Sw…

前端excel表格解析為json,并模仿excel顯示

前端環境&#xff1a;elementUI vue2 <style lang"scss" scoped> 頁面效果 jsondata為mock數據&#xff0c;為方便調試其內容可清空&#xff0c;首行&#xff08;字母坐標&#xff09;隨數據內容自動變化&#xff0c;首列也是一樣&#xff0c;模擬excel …

NAT(網絡地址轉換)邏輯圖解+實驗詳解

原理 NAT&#xff08;Network Address Translation&#xff0c;網絡地址轉換&#xff09; 是一種網絡技術&#xff0c;用于在IP數據包通過路由器或防火墻時&#xff0c;修改其源IP地址或目標IP地址&#xff0c;以實現不同網絡之間的通信。 基礎概念 本來NAT是來解決 IPv4 地…

Qt+線段拖曳示例代碼

Qt線段拖曳示例代碼&#xff0c;功能見下圖。 代碼如下&#xff1a; canvaswidget.h #ifndef CANVASWIDGET_H #define CANVASWIDGET_H#include <QWidget> #include <QPainter> #include <QMouseEvent> #include <QVector>class CanvasWidget : publi…

高等數學-求導

一、求導數的原函數就是求導數的積分 1&#xff09;設函數f(t)在區間[a,b]上連續&#xff0c;則對任意的x∈[a,b],f(t)在[a,x]上連續&#xff0c;從而在[a,x]上可積。令其積分為Φ(x)∫*a^x f(t)dt, x∈[a,b],則Φ(x)為定義在區間[a,b]上的一個函數&#xff0c;通常稱作積分上…

(第94天)OGG 微服務搭建 Oracle 19C CDB 架構同步

前言 Oracle GoldenGate Microservice Architecture (OGGMA) 是在 OGG 12.3 版本推出的全新架構。相比傳統架構,OGGMA 基于 Rest API,通過 WEB 界面即可完成 OGG 的配置和監控,大大簡化了部署和管理流程。 本文將詳細介紹如何在 Oracle 19C CDB 環境中部署 OGG 19.1.0.4 微…

前端vscode學習

1.安裝python 打開Python官網&#xff1a;Welcome to Python.org 一定要點PATH&#xff0c;要不然要自己設 點擊install now,就自動安裝了 鍵盤winR 輸入cmd 點擊確定 輸入python&#xff0c;回車 顯示這樣就是安裝成功了 2.安裝vscode 2.1下載軟件 2.2安裝中文 2.2.1當安…

uniapp vue 開發微信小程序 分包梳理經驗總結

嗨&#xff0c;我是小路。今天主要和大家分享的主題是“uniapp vue 開發微信小程序 分包梳理經驗總結”。 在使用 UniAppvue框架開發微信小程序時&#xff0c;當項目比較大的時候&#xff0c;經常需要分包加載。它有助于控制主包的大小&#xff0c;從而提升小程序的啟…

git合并多次commit提交

首先查看歷史記錄 git log 查看你想要合并的commit是哪些&#xff08;注意&#xff1a;這里是逆序&#xff0c;最上的是最新提交&#xff09; 找到當前想要合并的最后一個記錄&#xff0c;復制該記錄的下一個記錄的 id&#xff08;黃色部分commit id&#xff09;&#xff0c…

系統架構設計(七):數據流圖

定義 數據流圖&#xff08;Data Flow Diagram, DFD&#xff09;是一種用于表示信息系統數據流轉及處理過程的圖形工具。 它反映系統功能及數據之間的關系&#xff0c;是結構化分析與設計的重要工具。 主要符號 符號說明描述舉例方框外部實體&#xff08;源或終點&#xff09…