java高效实现爬虫

news2025/5/17 7:59:11

一、前言
在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>
<!-- 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() {
        // 自动下载与系统浏览器匹配的WebDriver
        WebDriverManager.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() {
        // 自动下载与系统浏览器匹配的WebDriver
        WebDriverManager.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:port
                    proxyUrl = "http://" + proxyUsername + ":" + proxyPassword + "@" + proxyHost + ":" + proxyPort;
                } else {
                    // 不带认证的代理格式:http://host:port
                    proxyUrl = "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);
    }
}

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() {
        // 自动下载与系统浏览器匹配的WebDriver
        WebDriverManager.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() {
        // 自动下载与系统浏览器匹配的WebDriver
        WebDriverManager.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:port
                    proxyUrl = "http://" + proxyUsername + ":" + proxyPassword + "@" + proxyHost + ":" + proxyPort;
                } else {
                    // 不带认证的代理格式:http://host:port
                    proxyUrl = "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=soi1rkc6rd82
        String 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或Firefox
            log.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("爬虫任务完成");
    }
}

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=soi1rkc6rd82
        String 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或Firefox
            log.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 配置代理的注意事项
在使用代理时,需要注意以下几点:

选择合适的代理类型:隧道代理适合大规模爬虫,普通代理适合小规模测试
正确配置认证信息:确保用户名和密码正确,特殊字符需要URL编码
测试代理连通性:使用前先测试代理是否可用
合理设置请求频率:遵循代理服务商的使用建议,避免触发反爬机制
注意IP切换时机:适时切换IP,避免同一IP频繁访问目标网站
六、总结与展望
本文详细介绍了如何使用Java+Selenium+快代理实现高效的网页爬虫。通过工厂模式和构建器模式的应用,我们实现了一个灵活、可扩展且易于使用的爬虫框架。该框架解决了代理认证配置的难题,优化了浏览器参数设置,提高了爬虫的稳定性和效率。

Selenium与代理服务的结合为我们提供了强大的爬虫能力:Selenium模拟真实用户行为应对JavaScript渲染和复杂交互,而快代理则提供了稳定的IP资源池,有效规避IP封禁和地域限制问题。这种组合特别适合需要处理登录验证、动态加载内容或有反爬措施的网站。

在实际应用中,请务必遵守相关法律法规和网站的使用条款,合理设置爬虫的请求频率和数量,避免对目标网站造成不必要的负担。同时,定期更新Selenium和WebDriver版本,以适应浏览器的更新和网站的变化。

如果你在使用过程中遇到问题,可以参考快代理或查阅Selenium的相关资料。希望本文对你的爬虫开发有所帮助!

最后,随着网站反爬技术的不断进化,爬虫技术也需要持续更新迭代。未来,我们可以考虑结合机器学习技术识别验证码,或通过更智能的策略调整爬取行为,使爬虫更加智能和高效。

欢迎在评论区分享你的使用经验和改进建议!


————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/weixin_66401877/article/details/147825058

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2377475.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

YOLOv3深度解析:多尺度特征融合与实时检测的里程碑

一、YOLOv3的诞生&#xff1a;继承与突破的起点 YOLOv3作为YOLO系列的第三代算法&#xff0c;于2018年由Joseph Redmon等人提出。它在YOLOv2的基础上&#xff0c;针对小目标检测精度低、多类别标签预测受限等问题进行了系统性改进。通过引入多尺度特征图检测、残差网络架构和独…

uniapp-商城-60-后台 新增商品(属性的选中和页面显示)

前面添加了属性&#xff0c;添加属性的子级项目。也分析了如何回显&#xff0c;但是在添加新的商品的时&#xff0c;我们也同样需要进行选择&#xff0c;还要能正常的显示在界面上。下面对页面的显示进行分析。 1、界面情况回顾 属性显示其实是个一嵌套的数据显示。 2、选中的…

虹科技术 | 简化汽车零部件测试:LIN/CAN总线设备的按键触发功能实现

汽车零部件测试领域对操作的便捷性要求越来越高&#xff0c;虹科Baby-LIN-RC系列产品为这一需求提供了完美的解决方案。从基础的按键设置到高级的Shift键应用&#xff0c;本文将一步步引导您了解虹科Baby-LIN-RC系列产品的智能控制之道。 虹科Baby-LIN-3-RC 想象一下&#xff0…

单片机ESP32天气日历闹铃语音播报

自制Arduino Esp32 单片机 可以整点语音播报&#xff0c;闹铃语音播报&#xff0c;农历显示&#xff0c;白天晚上天气&#xff0c;硬件有 Esp32&#xff0c;ST7789显示屏&#xff0c;Max98357 喇叭驱动&#xff0c;小喇叭一枚。有需要源码的私信我。#单片机 #闹钟 #嵌入式 #智能…

如何解决LCMS 液质联用液相进样器定量环漏液问题

以下是解决安捷伦1260液相色谱仪为例的进样器定量环漏液问题的一些方法&#xff1a;视频操作 检查相关部件 检查定量环本身&#xff1a;观察定量环是否有破损、裂纹或变形等情况。如果发现定量环损坏&#xff0c;需及时更换。检查密封垫&#xff1a;查看进样阀的转子密封垫、计…

服务器内部可以访问外部网络,docker内部无法访问外部网络,只能docker内部访问

要通过 iptables 将容器中的特定端口请求转发到特定服务器&#xff0c;你需要设置 DNAT&#xff08;目标地址转换&#xff09;规则。以下是详细步骤&#xff1a; 假设场景 容器端口: 8080&#xff08;容器内服务监听的端口&#xff09;目标服务器: 192.168.1.100&#xff08;请…

PCIe Switch 问题点

系列文章目录 文章目录 系列文章目录完善PCIe Retimer Overview Document OutlineSwitch 维度BroadComMicroChipAsmedia 祥硕Cyan其他 完善 Functional block diagram&#xff0c;功能框图Key Features and Benefits&#xff0c;主要功能和优点Fabric 链路Multi-root PCIe Re…

开源轻量级地图解决方案leaflet

Leaflet 地图&#xff1a;开源轻量级地图解决方案 Leaflet 是一个开源的 JavaScript 库&#xff0c;用于在网页中嵌入交互式地图。它以轻量级、灵活性和易用性著称&#xff0c;适用于需要快速集成地图功能的项目。以下是关于 Leaflet 的详细介绍和使用指南。 1. Leaflet 的核心…

Flutter目录结构介绍、入口、Widget、Center组件、Text组件、MaterialApp组件、Scaffold组件

目录 1. 创建Flutter项目 1.1使用Android Studio创建Flutter项目 1.2 使用命令行创建Flutter项目 2. Flutter项目介绍 2.1所有代码都在lib目录下编写 2.1 pubspec.yaml 依赖库/图片的引用 ​编辑 3. 运行项目 4. 编写mian.dart文件 4.1 使用MaterialApp 和 Scaffold两个组件…

如何实现金蝶云星空到MySQL的数据高效集成

金蝶云星空数据集成到MySQL的技术案例分享 在企业信息化建设中&#xff0c;数据的高效流动和准确处理是关键。本文将聚焦于一个具体的系统对接集成案例&#xff1a;金蝶云星空的数据集成到MySQL&#xff0c;方案名称为“xsck-2金蝶销售出库-->mysql”。通过这一案例&#x…

院校机试刷题第四天:1911反转公约数、1702十六进制不进位加法

一、1911反转公约数 1.题目描述 2.解题思路 两个关键点&#xff1a;1.如何把数字反转&#xff0c;2.如何求最大公约数。 反转&#xff1a;用字符串形式存储&#xff0c;定义一个新的字符串倒序存储反转之后的字符串&#xff0c;将字符串按位转换位数字。 求最大公约数&…

Redis解析

Redis解析 一、单线程模型 redis在io层面是多线程的&#xff0c;在数据处理层面是单线程的。 多线程一般用于&#xff1a; 关闭连接删除/淘汰内存网络IO 1.1 io多路复用 redis使用nio&#xff08;select、poll、epoll&#xff09;的方式处理socket 主线程负责接收建立连接…

2025年Ai写PPT工具推荐,这5款Ai工具可以一键生成专业PPT

上个月给客户做产品宣讲时&#xff0c;我对着空白 PPT 页面熬到凌晨一点&#xff0c;光是调整文字排版就改了十几版&#xff0c;最后还是被吐槽 "内容零散没重点"。后来同事分享了几款 ai 写 PPT 工具&#xff0c;试完发现简直打开了新世界的大门 —— 不用手动写大纲…

css:倒影倾斜效果

这是需要实现的效果&#xff0c;平时用的比较多的是添加阴影&#xff0c;是box-shadow&#xff0c;而添加倒影是box-reflect&#xff0c;需要注意的是box-reflect需要添加浏览器前缀&#xff0c;比如我用的谷歌浏览器&#xff0c;要加-webkit-才能生效。 -webkit-box-reflect:…

语音识别——通过PyAudio录入音频

PyAudio 是一个用于处理音频的 Python 库&#xff0c;它提供了录制和播放音频的功能。通过 PyAudio&#xff0c;可以轻松地从麦克风或其他音频输入设备录制音频&#xff0c;并将其保存为文件或进行进一步处理。 安装 PyAudio 在使用 PyAudio 之前&#xff0c;需要先安装它。可…

五月月报丨MaxKB在教育行业的应用进展与典型场景

在2025年的3月和4月的“用户应用月度报告”中&#xff0c;MaxKB开源项目组相继总结了MaxKB开源项目在政府、公共事业、教育、医疗以及企事业单位的应用情况。毫无疑问&#xff0c;在DeepSeek等国产大模型被各行各业的用户广泛接受之后&#xff0c;AI应用建设并运营的步伐也在显…

【流程控制结构】

流程控制结构 流程控制结构1、顺序结构2、选择结构if基本选择结构if else语法多重if语法嵌套if语法switch选择结构 3、循环结构循环结构while循环结构程序调试for循环跳转语句区别 流程控制结构 1、顺序结构 流程图 优先级 2、选择结构 if基本选择结构 单if 语法 if&…

PowerBI基础

一、前言 在当今数据驱动的时代&#xff0c;如何高效地整理、分析并呈现数据&#xff0c;已成为企业和个人提升决策质量的关键能力。Power BI 作为微软推出的强大商业智能工具&#xff0c;正帮助全球用户将海量数据转化为直观、动态的可视化洞察。数据的世界充满可能性&#xf…

一文了解多模态大模型LLaVA与LLaMA的概念

目录 一、引言 二、LLaVA与LLaMA的定义 2.1 LLaMA 2.2 LLaVA 2.3 LLaVA-NeXT 的技术突破 三、产生的背景 3.1 LLaMA的背景 3.2 LLaVA的背景 四、与其他竞品的对比 4.1 LLaMA的竞品 4.2 LLaVA的竞品 五、应用场景 5.1 LLaMA的应用场景 5.2 LLaVA的应用场景 六…

原生小程序+springboot+vue+协同过滤算法的音乐推荐系统(源码+论文+讲解+安装+部署+调试)

感兴趣的可以先收藏起来&#xff0c;还有大家在毕设选题&#xff0c;项目以及论文编写等相关问题都可以给我留言咨询&#xff0c;我会一一回复&#xff0c;希望帮助更多的人。 系统背景 在数字音乐产业迅猛发展的当下&#xff0c;Spotify、QQ 音乐、网易云音乐等音乐平台的曲…