基于selenium与firefox的爬虫实现方案
Posted 黑六
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于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<ChainedProxy> 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: ["<all_urls>"]}, [\'blocking\'] );
方案3中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);
}
}
六、保留标签页可能会导致cpu长时间占用
在访问完网页之后,如果不关闭对应的标签页,那么浏览器可能会保持较高的cpu消耗
解决方案:访问完网页之后,关闭标签页,只保留一个浏览器空白标签页
七、firefox隐藏 window.navigator.webdriver
firefox 88以下版本,firefox提供配置参数
profile.addPreference("dom.webdriver.enabled", false)
firefox 88以上版本
可以利用以下js实现屏蔽
Object.defineProperties(navigator, {webdriver:{get:()=>undefined}});
但是如果在页面加载完再利用selenium执行js,是起不到效果的,因为网站加载完就会执行相关js,获取到window.navigator.webdriver的值
所以需要拦截相关js请求,在每个js返回内容前加上上面js,达到效果。具体可以利用browsermob-proxy实现。
以上是关于基于selenium与firefox的爬虫实现方案的主要内容,如果未能解决你的问题,请参考以下文章