基于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);
}
}
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- Docker应用:容器间通信与Mariadb数据库主从复制
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量
- 第326天
- Shell-Bash变量与运算符
- 基于微信小程序带后端ssm接口小区物业管理平台设计
- 基于|基于 antd 风格的 element-table + pagination 的二次封装
- 逻辑回归的理解与python示例
- Guava|Guava RateLimiter与限流算法
- 我和你之前距离