基于selenium与firefox的爬虫实现方案

百度对selenium的定义: Selenium是一个用于Web应用程序测试的工具。所以爬虫在生产环境使用selenium的时候会遇到一些问题,以下是我在使用的时候遇到的问题以及解决方案,针对这些问题我也开源了一个selenium的使用工具,该工具是基于selenium-java的封装, 地址:https://gitee.com/wangyelou/S...

相关问题及方案

浏览器频繁启动关闭性能消耗大
解决方案: 创建浏览器对象池管理浏览器,用完浏览器后不立即销毁,而是放入池中供下次调用,为了防止浏览器运行时间长而导致的一些意想不到的情况,可以每隔一段时间对浏览器进行重启操作。
而每次使用浏览器不销毁,会有一系列的问题,下面会一一阐述。
selenium没有提供在线自动切换代理的方法
selenium代理设置是在浏览器创建的时候配置的,对于正在运行的浏览器selnenium并没有切换代理的方法
解决方案: firefox支持在about:config页面使用js切换代理, selenium可以跳转到该页面然后执行相关js代码,从而实现在线切换代理
// js在 about:config 页面设置firefox代理
var prefs = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefBranch);
prefs.setIntPref('network.proxy.type', 1);
prefs.setCharPref('network.proxy.http', '127.0.0.1');
prefs.setIntPref('network.proxy.http_port', 1234);
prefs.setCharPref('network.proxy.ssl', '127.0.0.1');
prefs.setIntPref('network.proxy.ssl_port', 1234);
代理认证问题
  • 方案1: 基于firefox 60 以下版本, selenium可以获取弹窗对象,输入用户名和密码,再点击确认按钮
  • 方案2:利用browsermob-proxy做代理转发,在browsermob-proxy层做代理认证

    BrowserMobProxyServer bmpServer = new BrowserMobProxyServer();
    
    bmpServer.setChainedProxyManager(new ChainedProxyManager() {
        public void lookupChainedProxies(HttpRequest httpRequest, Queue chainedProxies) {
            chainedProxies.add(new ChainedProxyAdapter() {
                @Override
                public InetSocketAddress getChainedProxyAddress() {
                    return new InetSocketAddress("127.0.0.1", 7000);
                }
    
                @Override
                public void filterRequest(HttpObject httpObject) {
                    if (httpObject instanceof HttpRequest) {
                        HttpHeaders.addHeader((HttpRequest)httpObject, HttpHeaders.Names.PROXY_AUTHORIZATION, "Basic " + BrowserMobHttpUtil.base64EncodeBasicCredentials("username", "password"));
                    }
                }
            });
        }
    });
    
    bmpServer.setTrustAllServers(true);
    bmpServer.start(888);
  • 方案3:基于firefox api制作插件, 在浏览器层面做代理认证
    https://developer.mozilla.org...

    function callbackFn1(details) {
        console.log(username);
        return {
            authCredentials: {
                username: "username",
                password: "password"
            }
        };
    }
     
    chrome.webRequest.onAuthRequired.addListener(
            callbackFn1,
            {urls: [""]},
            ['blocking']
    );

    firefox 加载插件问题:

    • 加载的插件必须经过官方的签名,否则只能使用插件调试功能
    • selenium 以临时插件的方式加载的(重写firefoxwebdriver 方法)

          public String installExtension(Path path) {
              return (String) execute(INSTALL_EXTENSION,
                      ImmutableMap.of("path", path.toAbsolutePath().toString(),
                              "temporary", true)).getValue();
          }
兼容网页和文件下载
文件下载会直接下载到本地目录,这时通过getPageSource()无法获取相关内容
解决方案:每个浏览器设置自己唯一的下载目录,当访问完网页后,检测下载目录是否有文件,有则代表是下载文件

selenium设置文件自动下载

surrogate.addPreference("browser.download.folderList", 2);
surrogate.addPreference("browser.download.dir", setupConfig.getDownDir(uid));
surrogate.addPreference("browser.download.useDownloadDir", true);
surrogate.addPreference("browser.download.manager.showWhenStarting", false);
surrogate.addPreference("browser.helperApps.neverAsk.saveToDisk", "application/octet-stream, application/x-001...");
窗口错误

当当前窗口关闭时,selenium无法感知到, 这时如果对页面进行操作会抛出NoSuchWindow异常

解决方案:重写execute方法

while (true) {
    try {
        return super.execute(driverCommand, parameters);
    } catch (NoSuchWindowException e) {
        String s = getWindowHandles().toArray()[0].toString();
        switchTo().window(s);
        System.out.println(s);
        parameters = ImmutableMap.of("handle", s);
    }
}

你可能感兴趣的:(爬虫seleniumjava)