
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 的回调函数处理。代码如下: