scrapy定制爬虫-爬取javascript内容

很多网站都使用javascript…网页内容由js动态生成,一些js事件触发的页面内容变化,链接打开.甚至有些网站在没有js的情况下根本不工作,取而代之返回你一条类似”请打开浏览器js”之类的内容.

对javascript的支持有四种解决方案:
1,写代码模拟相关js逻辑.
2,调用一个有界面的浏览器,类似各种广泛用于测试的,selenium这类.
3,使用一个无界面的浏览器,各种基于webkit的,casperjs,phantomjs等等.
4,结合一个js执行引擎,自己实现一个轻量级的浏览器.难度很大.

对于简单的有限爬取任务,若可以通过代码模拟js逻辑,首选这种方案,例如,在duckduckgo搜索引擎中,翻页这个动作是靠js触发的.模拟似乎还是很难,然后我注意到他页面的第二个form,似乎submit后就可以翻页,试了一下果然如此.
在写代码模拟相关js逻辑时,首先试下关闭浏览器的js,看下是否能获取到需要的东西.有些页面提供了没有js的兼容.不行再开chrome的控制台或firebug观察js逻辑,可能是ajax这类收发包.用urllib2(推荐requests库)模拟即可,也可能是修改dom之类,用lxml这类对应修改即可.说来就是js执行了什么,就用python代码对应模拟执行.

也可选择使用selenium这类,缺点是效率很低,你应当先测试一下selenium启动一个浏览器实例所需时间你是否可接受.这个时间一般在秒级别.再考虑到浏览器打开页面渲染,就更慢了.在效率可接受的前提下,这个方案也不错.
这个方案的另一个问题是在没有桌面环境的服务器上,selenium目测无法运行.

对规模不小,模拟js不可行,selenium效率太低,或需要在无桌面环境上执行的情况.有无界面浏览器,几个无界面浏览器大体情况如下:
1,casperjs,phantomjs:非py,可以通过命令行调用,功能基本满足,推荐先看下这两个是否满足.比较成熟.phantomjs还有一个非官方的webdriver协议实现,由此可通过selenium调phantomjs实现无界面.
2,ghost,spynner等:py定制的webkit,个人觉得spynner代码乱,ghost代码质量不错.但有bug.我看过几个这类库后自己改了一个.
这种方案的详细情况见下面.

最后还有一种选择,在js执行引擎的基础上,自己实现一个轻量级的支持js的无界面浏览器.除非你有非常非常非常多需要爬取的内容,效率十分十分十分重要.若你有这个想法,可以看下pyv8,在v8的示例代码中有一个基于v8实现的简易浏览器模型.是的,只是个模型,并不完全可用,你要自己填充里面的一些方法.实现这些你需要在js引擎(v8),http库(urllib2)之上实现这些功能,1,当网页打开时获取其包含的js代码,2,构建一个浏览器模型,包括各种事件与dom树.3,执行js.除此之外可能还有其他一些细节.难度较大.
网上可以找到一淘所用购物比价爬虫的一篇相关ppt.该爬虫也仅使用的第三种方案.可以看下这篇ppt.该爬虫大概是用的webkit,scrapy,另外把scrapy的调度队列改为基于redis的,实现分布式.

如何实现:

回头谈点背景知识,scrapy使用了twisted.一个异步网络框架.因此要留意潜在的阻塞情况.但注意到settings中有个参数是设置ItemPipeline的并行度.由此推测pipeline不会阻塞,pipeline可能是在线程池中执行的(未验证).Pipeline一般用于将抓取到的信息保存(写数据库,写文件),因此这里你就不用担心耗时操作会阻塞整个框架了,也就不用在Pipeline中将这个写操作实现为异步.
除此之外框架的其他部分.都是异步的,简单说来就是,爬虫生成的请求交由调度器去下载,然后爬虫继续执行.调度器完成下载后会将响应交由爬虫解析.

网上找到的参考例子,部分将js支持写到了DownloaderMiddleware中,scrapy官网的code snippet也是这样 .若这样实现,就阻塞了整个框架,爬虫的工作模式变成了,下载-解析-下载-解析,而不在是并行的下载.在对效率要求不高的小规模爬取中问题不大.
更好的做法是将js支持写到scrapy的downloader里.网上有一个这样的实现(使用selenium+phantomjs).不过仅支持get请求.

在适配一个webkit给scrapy的downloader时,有各种细节需要处理.

点赞