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