基于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异常
【基于selenium与firefox的爬虫实现方案】解决方案:重写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); } }

    推荐阅读