简单的Selenium访问控制线程池

思路:频繁开关phantomJS进程比较耗费资源,所以需要维护一个线程池控制访问以减少内存消耗


1. 自定义操作CustomAction接口

public interface CustomAction {
    String action(WebDriver webDriver);
}

2. WebDriverPool池

public class WebDriverPool {

    // 线程池大小
    private static final int MAX_COUNT = 15;
    // 线程数量控制
    private Semaphore semaphore = new Semaphore(MAX_COUNT);
    // webDriver池
    private WebDriver[] webDrivers = new WebDriver[MAX_COUNT];

    private boolean[] driverFlag = new boolean[MAX_COUNT];

    private Lock lockDrivers = new ReentrantLock();

    //phantomjs路径
    private final String JS_BIN = "f:/phantomjs";

    public WebDriverPool() {
        System.setProperty("phantomjs.binary.path", JS_BIN);
        for (int i = 0; i < MAX_COUNT; i++) {
            driverFlag[i] = true;
        }
        // 关闭所有打开的浏览器
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            for (WebDriver webDriver : webDrivers) {
                if (webDriver != null) {
                    webDriver.quit();
                }
            }
        }));
    }

    /**
     * 生成一个新的PhantomJSDriver
     */
    private WebDriver defaultDriver() {
        DesiredCapabilities cap = DesiredCapabilities.phantomjs();
        // 优化命令行参数
        List cmdList = new ArrayList<>();
        // 禁用图片
        cmdList.add("--load-images=false");
        // 本地缓存
        cmdList.add("--disk-cache=true");
        cap.setCapability("phantomjs.cli.args", cmdList);
        return new PhantomJSDriver(cap);
    }

    /**
     * 获取当前空闲的driver的下标
     *
     * @return 当前空闲的driver的下标
     */
    private int freeDriverIndex() {
        int ret = -1;
        try {
            lockDrivers.lock();
            for (int i = 0; i < driverFlag.length; i++) {
                if (driverFlag[i]) {
                    driverFlag[i] = false;
                    ret = i;
                    break;
                }
            }
            if (ret != -1) {
                if (webDrivers[ret] == null) {
                    webDrivers[ret] = defaultDriver();
                }
            }
        } finally {
            lockDrivers.unlock();
        }
        return ret;
    }

    /**
     * 获取执行js之后的页面html
     */
    public String customJs(CustomAction action) {
        String html = "";
        try {
            semaphore.acquire();
            int index = freeDriverIndex();
            //调用自定义的操作
            html = action.action(webDrivers[index]);
            driverFlag[index] = true;
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release();
        }
        return html;
    }

}

缺点:

1.不能在运行时自由伸缩线程池中的资源,也就是不能在闲时销毁池中的资源减少内存消耗 ,运行时不能很好地伸缩

2.每个PhantomJS进程只运行了一个窗口,比较浪费,可以通过PhantomJSDriverService结合RemoteWebDriver的方式支持更高的并发

3.考虑使用apache commons pool2实现



你可能感兴趣的:(踩过的坑,java多线程,爬虫开发)