Selenium 的 Webdriver 爬取动态网页效果虽然不错,但效率方面并不如人意。最近一直研究如何提高动态页面爬虫的效率,方法无非高并发和分布式两种。过程中有很多收获,也踩了不少坑,在此一并做个总结。以下大致是这段时间的学习路线。

一、 Scrapy+phantomJS

Scrapy 是一个高效的异步爬虫框架,使用比较广泛,文档也很完备,开发人员能快速地实现高性能爬虫。关于 Scrapy 的基本使用这里就不再赘述了, 这篇 Scrapy 读书笔记 挺不错的。然而 Scrapy 在默认的情况下只能获取静态的网页内容,因此必须进一步定制开发。

Scrapy 结合 phantomJS 似乎是个不错的选择。phantomJS 是一个没有页面的浏览器,能渲染动态页面并且相对轻量。因此,我们需要修改 Scrapy 的网页请求模块,让 phantomJS 请求网页,以达到获取动态网页的目的。一番调研之后,发现大致有三种定制方法:

1. 每个 url 请求两次。在回调函数中舍弃掉返回的 response 内容,然后用 phantomJS 再次请求 response.url,这次的请求由于没有构造 Request 对象,当然就没有回调函数了,然后阻塞等待结果返回即可。这个方法会对同一个 url 请求两次,第一次是 Scrapy 默认的 HTTP 请求,第二次则是 phantomJS 的请求,当然第二次获取到的就是动态网页了。这个方法比较适合快速实现小规模动态爬虫,在默认的 Scrapy 项目基础上,只需要简单修改回调函数就可以了。

2. 自定义下载中间件( downloadMiddleware)。 downloadMiddleware 对从 scheduler 送来的 Request 对象在请求之前进行预处理,可以实现添加 headers, user_agent,还有 cookie 等功能 。但也可以通过中间件直接返回 HtmlResponse 对象,略过请求的模块,直接扔给 response 的回调函数处理。代码如下:

改完代码后,记得修改 settings 配置。但这个方法有个很大的问题---- 不能实现异步爬取。由于直接在下载中间件中请求网页,而 Scrapy 在这里却不是异步的,只能实现阻塞式的逐个网页下载。当然,如果不追求高并发的话,这也是个快速部署动态爬虫的方法。

3.自定义 downloader downloader 是 Scrapy 发起 HTTP 请求的模块,这模块实现了异步请求,因此自定义 downloader 是最完美的实现。但是要编写一个自定义的 downloader比较麻烦,必须按照 Twisted 的一些规范,所幸网上有一些开源的 downloader,在这基础上改改就比较容易了。 这篇文章 详解了 downloader 的开发,非常不错!

一些坑和心得

  1. 通过代码运行 Scrapy 是个很有用的方法,即通过 CrawlerProcess 类运行爬虫,但是给 Spider 传递 settings 参数却是一个很大的坑,这个问题绕了我很长时间,最后的解决方法是修改 PYTHONPATH 和 SCRAPY_SETTINGS_MODULE 环境变量,加上爬虫项目的目录,这样 Python 才能找到配置文件。

  2. 设置 DOWNLOAD_TIMEOUT 选项,其默认值是 180 秒,相对较长,可以设置得短一些提高效率。

  3. PhantomJS 对多进程的支持极不稳定。具体表现在如果一主机同时开了多个 phantomJS 进程,单个 phantomJS 运行结果就会时好时坏,经常出现一些莫名其妙的报错,官方 git 的 issue 上也提到 phantomJS 对多进程的支持很不好。如果真要多进程爬虫的话,推荐 chromedriver。

  4. Scrapy 的优势在于高效的异步请求框架,由于其本身并不支持动态页面爬取,如果对爬虫的效率没有特别高的要求,也没有必要一定用这个框架,毕竟熟悉框架要一定的时间成本,在框架下编程限制也比较多,对一些比较简单的爬虫,有时还不如自己手撸一个。

二、 Scrapy-splash

由于 phantomJS 的多并发短板,Scrapy+phantomJS 的效率受限,因此,这并不是一个特别好的选择。

又一番调研后,发现 splash 似乎是个不错的选择。Splash 是一个 Javascript 渲染服务。它是用 Python 实现的,同时使用了 Twisted 和 QT,并且实现了 HTTP API的轻量浏览器,Twisted(QT)用来让服务具有异步处理能力,以发挥 webkit 的并发能力。

一般来说,在 Scrapy 中只需要返回一个 SplashRequest 对象即可。比如:

同样也可以返回带 POST 参数的 Request 对象。更简单地,用 urllib 等库构造 POST 请求也没问题,因为这本质上是一个端口代理,可以接受任何的 HTTP 请求。

splash 的内存占用相对较少,但多并发仍然会出现些问题,请求的失败率会大大提高,页面渲染结果偶尔会出现一些问题,同时受制于服务器主机的带宽,速度受限,但总体表现不错,足以应对小规模的动态爬虫。

Splash 的优点也很显著,通过 HTTP API,其他分布式节点能很容易地获得动态页面,并且使得服务器和其他节点之间的耦合降到了最低,扩展变得特别方便。另外,分布式节点不用配置环境就能获得动态页面,相对 phantomJS 复杂的配置来说简单太多了!如果想简单地实现动态页面爬虫,splash 是一个非常好的选择,但受制于单个服务器带宽,速度有限,并且有时渲染效果不是很理想。

三、 chromedriver 并发

无论 phantomJS 还是 splash,稳定性是一方面,在渲染效果和速度上都不及 chromedriver,毕竟 V8 引擎不是盖的!但 chromedriver 缺点也很明显----特别耗内存,而且是有界面的!

有段时间为了爬百度搜索结果,我一开始用 requests 库模拟 POST 请求,虽然效率没问题,但经常被百度封,于是试着改用 phantomJS,当时觉得尽管效率低了点,但毕竟是真正的浏览器,百度应该不会封。后来发现作用也不大,还是经常被封,并且 phantomJS 自身不太稳定,经常报错,多进程并发更是没办法运行。看来只能试一试 chromedriver 了。以前一直忌惮于内存杀手 chrome(开一个 chrome 浏览器,任务管理器里就有很多个 chrome 进程),最后无奈只能祭出这大杀器了。跑了一段时间之后,发现 chrome 的效率还挺不错,占用的内存也没有想象中的大,多并发支持非常好,在我的电脑上同时开 20 来个也没问题,稳定性也不错,而且百度居然就没封!(震惊!!!chrome 居然自带反反爬虫光环!)。但由于程序主要在阿里云主机上跑,有界面的 chromedriver 当时便没有考虑在内,前不久才知道原来可以通过引入虚拟界面,让 chrome 在没有界面的主机上跑.....

Python 的 pyvirtualdisplay 库就能引入虚拟界面。 
代码实现也非常简单:

经个人测试,发现 chrome 对多进程的支持非常好,渲染速度快,就是内存占用相对较大,可以多进程+分布式提高效率,关键 chrome 不容易被封。

PS. 常用的 chromedriver 关闭图片选项代码:

四、Selenium Grid

Selenium Grid 是 Selenium 的单机扩展,允许用户将测试案例分布在几台机器上并行执行。当然,能实现分布式测试,分布式爬虫当然没问题。 
Selenium Grid 的机制如图。首先启动一个中央节点(Hub),然后启动多个远程控制节点(rc),并让 rc 在 Hub 上注册自己的信息,包括 rc 自身的系统、支持的 webdriver、最大并发数量等,这样 Hub 节点就知道了所有的 rc 信息,方便以后调度。

Selenium Grid 机制

运行环境搭建好之后,测试或爬虫脚本请求 Hub 的服务端口,Hub 主机根据注册的 rc 节点的当前状态,结合负载均衡原则,将这些测试用例分发到指定的 rc 节点,rc 节点接到命令之后便执行。

from selenium import webdriverurl = "http://localhost:4444/wd/hub"driver = webdriver.Remote(command_executor = url, desired_capabilities = {'browserName':'chrome'})driver.get("http://www.baidu.com")print driver.title

如下图,我在本地建立了一个 Hub 节点,默认端口是 4444,接着用本机注册了两个 rc 节点,端口分别为 5555、6666。通过 hub 服务端口的控制台可以看到,每个节点可以支持 5 个 Firefox 实例、一个 IE 实例和 5 个 Chrome 实例(可以自定义)。由于本机没有安装 Opera 浏览器,当然也就没有 Opera 实例了。

Selenium Grid 控制台页面

Selenium Grid 是个很好的实现分布式测试/动态爬虫的框架,原理和操作也不复杂,有兴趣的同学可以多了解了解。

五、 总结

以上各软件或框架的特点简要如下:

  1. phantomJS 比较轻量,但对多并发支持非常差

  2. chromedriver 渲染速度快,多并发支持较好,但占用内存大

  3. splash 实现了 HTTP API,分布式扩展容易,页面渲染能力一般

  4. Selenium Grid 是专业的测试框架,扩展容易,支持负载均衡等高级特性

所以,分布式 Scrapy+chromedriverSelenium Grid是实现分布式动态爬虫较好的选择。

Python分布式动态页面爬虫研究相关推荐

  1. 京东动态页面爬虫 scrapy+selenium

    京东动态页面爬虫 大家都知道,京东页面抓取是需要下拉滑块才能加载完全的,今天给大家分享一下用scrapy+selenium进行数据的抓取. 京东页面的解析很简单,相信大家都会xpath或者正则,bs4 ...

  2. python selenium 动态页面处理 中标项目信息获取

    需求 为了寻找本地业务合作伙伴,在江西公共资源交易网提取相关项目信息,统计各公司中标信息. 因为关键字搜索后页面为动态页面 即翻页不会使网址发生变化 故使用selenium自动化脚本爬取信息 爬虫完整 ...

  3. 【Python】Python下载动态页面图片

    1.搭建Selenium环境: pip install selenium 到D:\python3.6.5\Lib\site-packages下把selenium文件夹复制到D:\python3.6.5 ...

  4. apache的基本配置和动态页面配置

    文章目录 Apache 了解Apache的基本配置 配置文件的功能介绍 编辑http的配置文件:`vi /etc/httpd/conf/httpd.conf` 查看监听的默认端口:`netstat – ...

  5. python爬虫翻页代码 豆瓣_Python爬虫 豆瓣动态页面的爬取

    动态页面和静态页面可通过检查元素查看爬取的信息和查看源代码中的信息是否一致,一致则为静态页面,反则为动态页面.因为检查查看的代码是经过处理后生成的,而查看源代码形式是你实际抓取的页面. 1.爬虫思路 ...

  6. 基于python爬虫————静态页面和动态页面爬取

    基于python爬虫----静态页面和动态页面爬取 文章目录 基于python爬虫----静态页面和动态页面爬取 1. 爬虫的原理 2. 用正则表达式匹配获取数据 3. 页面源码解析 4. 通过req ...

  7. python获取动态数据采集仪代理_Python3爬虫技术文档(3)——动态页面数据采集,三,获取...

    上文说到,我们可以通过分析Ajax访问服务器的方式来获取Ajax数据.Ajax也算动态渲染页面的一种.所以,动态页面也是可以爬取滴. Selenium Selenium是一个用于Web应用程序测试的工 ...

  8. python动态爬取知乎_python爬虫从小白到高手 Day2 动态页面的爬取

    今天我们说说动态页面的抓取,动态页面的概念不是说网页上的内容是活动的,而是刷新的内容由Ajax加载,页面的URL没有变化,具体概念问度娘. 就以男人都喜欢的美女街拍为例,对象为今日头条. chrome ...

  9. python 爬虫模拟点击_爬虫——模拟点击动态页面

    动态页面的模拟点击: 以斗鱼直播为例:http://www.douyu.com/directory/all 爬取每页的房间名.直播类型.主播名称.在线人数等数据,然后模拟点击下一页,继续爬取 #!/u ...

最新文章

  1. 【c语言】蓝桥杯算法提高 输出三个整数的最大数
  2. CentOS6.5 安装 ntopng
  3. Git使用汇总之暂存区工作区撤销和删除
  4. 排序的稳定性(概念明晰)
  5. MySQL中的整数类型
  6. 济南泉水与城市生态主题 第四届泉水文化论坛第二次会议
  7. java 微信群发多图文_[Java教程]httpClient实现微信公众号消息群发
  8. Linux怎么更新镜像,利用 Zsync 更新已有的 Ubuntu ISO 镜像
  9. nuxt的asyncdata页面刷新params数据丢失_React navigation goBack方法返回刷新
  10. OpenGL+VS2012环境搭建
  11. linux下复制文件并重命名,linux复制文件并修改文件名
  12. 一步一步编写12306抢票软件
  13. linux中如何升级驱动程序,Redhat 如何升级显卡驱动?
  14. ps3无限服务器连接,[攻略] (转) [分享] PS3常见错误代码及解决办法
  15. python数据分析:客户价值分析案例实战
  16. halcon测量总结
  17. linux的系统监视器图片_用Nvidia Jetson Nano 2GB和Python构建一个价值60美元的人脸识别系统 - 人工智能遇见磐创...
  18. 解决Pytorch转onnx错误:Only tuples, lists and Variables are supported as JIT inputs/outputs!
  19. 信数金服决策引擎分享(二):灰度发布-冠军/挑战者试验的另一个应用
  20. 设计模式学习(全)-七大基本原则-23种设计模式 超两万字总结!

热门文章

  1. notepad运行c语言教程,notepad怎么运行c语言
  2. “海外围猎场”里的中国游戏玩家
  3. ASUS华硕天选2 FX506H INTELI711代CPU 原装出厂系统恢复原厂系统
  4. 陈丹琦 关系抽取 2020 sota ner
  5. JAVA计算机毕业设计演唱会购票系统计算机(附源码、数据库)
  6. Redis---Redis三种常用数据结构
  7. Android项目大全
  8. Ubuntu下安装Stm32的Eclipse的开发环境(1)
  9. Python有道智云API图片文字识别
  10. 又是一个相当 带劲的招聘起事