更多>>关于我们
西安鲲之鹏网络信息技术有限公司从2010年开始专注于Web(网站)数据抓取领域。致力于为广大中国客户提供准确、快捷的数据采集相关服务。我们采用分布式系统架构,日采集网页数千万。我们拥有海量稳定高匿HTTP代理IP地址池,可以有效获取互联网任何公开可见信息。
您只需告诉我们您想抓取的网站是什么,您感兴趣的字段有哪些,你需要的数据是哪种格式,我们将为您做所有的工作,最后把数据(或程序)交付给你。
数据的格式可以是CSV、JSON、XML、ACCESS、SQLITE、MSSQL、MYSQL等等。
更多>>技术文章
什么是GeckoDriver?
如果你用过Selenium + Firefox,那你应该对geckodriver.exe(Linux下是geckodriver)不陌生。 如下图所示, GeckoDriver起着一个“Selenium测试脚本”与“火狐浏览器”沟通的中间桥梁作用:
- GeckoDriver提供了一个HTTP API接口,使用W3C WebDriver协议。
- Selenium通过W3C WebDriver协议和GeckoDriver进行交互(提交命令,获取结果)。
- GeckoDriver使用Firefox Remote协议与Firefox浏览器进行交互,转发Selenium的命令和火狐浏览器的应答。
更形象的解释:
- 1. "Selenium"是一个只会说“W3C WebDriver协议”话的人;
- 2. “火狐浏览器”是一个只会说“Firefox Remote协议”话的人;
- 3. "GeckoDriver"是一个翻译,它通晓“W3C WebDriver协议”和“Firefox Remote协议”两门语言;
- 4. 在GeckoDriver的帮助下,Selenium能够和火狐浏览器进行无障碍沟通;
什么是远程GeckoDriver?
默认GeckoDriver监听127.0.0.1:4444(如下图所示),因此只能够本地连接。
可用通过--host和--port参数来指定监听的IP和端口。比如监听0.0.0.0:56600:
geckodriver --host 0.0.0.0 --port 56600
这样我们就能远程访问这个GeckoDriver接口,进而能够在远程主机调用GeckoDriver所在机器上的Firefox浏览器。如下图所示:
为什么需要远程GeckoDriver?
设想一下,我们拥有一个20台服务器组成的爬虫集群,每个服务器上启动20个浏览器实例,总共就有400个浏览器。我们该如何有效地控制这400个浏览器呢?
按照传统的方式我们需要在每台服务器上部署Selenium脚本,通过本地GeckoDriver调用各自的20个浏览器,这似乎也没什么问题。但是,如果我们修改了爬虫脚本或者需要更换代理列表,就要在20台机器上重新部署一遍,首先要更新相关文件,然后要杀掉之前的爬虫进程,再启动新的进程,20台机器挨个操作一遍非常繁琐(而且很容易遗漏)。
使用远程GeckoDriver就可以避免这个问题,我们只需要在一台机器上部署Selenium相关脚本,然后通过远程调用这400个浏览器即可。后续修改代码也仅需要在这一台机器上做变更。
如何使用远程GeckoDriver?
Selenium.webdriver.Firefox默认启动并使用本地GeckoDriver,不支持远程GeckoDriver。需要我们稍作修改,代码如下所示:
# coding: utf-8 # test.py from selenium import webdriver from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver from selenium.webdriver.common.desired_capabilities import DesiredCapabilities class FirefoxRemoteWebDriver(webdriver.Firefox): """调用火狐远程geckodrivery服务 """ def __init__(self, remote_url, firefox_profile=None, timeout=30, capabilities=None, options=None, firefox_options=None): self.remote_url = remote_url if firefox_options: options = firefox_options self.binary = None self.profile = None class Service: def __init__(self): pass def stop(self): pass self.service = Service() if capabilities is None: capabilities = DesiredCapabilities.FIREFOX.copy() if options is None: options = webdriver.firefox.options.Options() if firefox_profile is not None: options.profile = firefox_profile capabilities = dict(capabilities) capabilities.update(options.to_capabilities()) executor = webdriver.firefox.remote_connection.FirefoxRemoteConnection(remote_server_addr=self.remote_url) RemoteWebDriver.__init__( self, command_executor=executor, desired_capabilities=capabilities, keep_alive=True) self._is_remote = False if __name__ == '__main__': # test options = webdriver.firefox.options.Options() # Headless模式 - 不显示浏览器UI options.set_headless(True) # 使用远程GeckoDriver, 接口地址:http://123.138.107.217:56600 firefox = FirefoxRemoteWebDriver(remote_url='http://123.138.107.217:56600', options=options) firefox.get('http://httpbin.org/ip') firefox.save_screenshot('test.png') print firefox.page_source
如下图所示是上述测试代码运行保存下来的屏幕截图文件test.png:
结合我们在项目中遇到的各种问题,我们对Selenium.webdriver.Firefox进行了重新封装,更加便于在爬虫项目中使用。
代码(firefox.py)在这里:https://bitbucket.org/qi/ghostkzp/src/ef4134889a4d89d613b89fa5aafe2c66dce7809f/firefox.py?at=default&fileviewer=file-view-default
主要有如下特点:
- 支持代理HTTP Proxy Basic Authentication,支持两种实现方式;
- 可以禁用图片加载;
- 可以隐藏浏览器UI(headless模式);
- 设置浏览器UA;
- 支持远程GeckoDriver调用;
- 支持导出/导入Cookie文件;
GeckoDriver管理器
为了便于管理GeckoDriver进程,我们编写了一个管理脚本,它通过Web API接口提供如下功能:
(1) /ports/
返回所有GeckoDriver监听端口,JSON格式。
(2) /restart/
重启指定的GeckoDriver进程(根据端口对应),并关闭对应的Firefox进程。用以解决远程连接GeckoDriver出现Session is already started问题。
GeckoDrive管理器(geckodriver_service.py)的代码:https://bitbucket.org/qi/ghostkzp/src/ef4134889a4d89d613b89fa5aafe2c66dce7809f/service/geckodriver_service.py?at=default&fileviewer=file-view-default
用法:
python geckodriver_service.py
程序运行后默认启动10个GeckoDriver进程,依次监听56600 ~ 56609 端口。并在5363端口提供Web API服务。
我们只需要将其添加到每个爬虫服务器自启动服务中即可。为了安全起见,需要使用iptables配置相应的IP白名单,只允许授权的IP访问。
查看可用GeckoDriver端口:
访问http://主机IP:5363/ports/, 返回如下图所示:
重启指定的GeckoDriver进程:
例如 重启56600端口对应的GeckoDriver。访问 http://主机IP:5363/restart/56600/。
PS:上述的"主机IP"指的是运行geckodriver_service.py的机器IP。
参考文章:
https://github.com/mozilla/geckodriver
https://w3c.github.io/webdriver/#protocol
https://firefox-source-docs.mozilla.org/testing/marionette/Protocol.html