前段时间用casperjs来抓取行业数据,现在整理温习一下。因为如果不这样,用过的东西又很快就忘了,不利于知识的积累。casperjs是基于PhantomJS的,个人觉得PhantomJS文档不是很用户友好,相对casperjs有api文档可以查就好很多了。http://casperjs.readthedocs.org/en/latest/modules/casper.html
首先创建一个对象。这是一个经典的代码开头:
varcasper = require('casper').create({
stepTimeout:40000,
verbose:true,
onError:function(self, m) { // Any "error" level message will bewritten
console.log('FATAL:'+ m); // on the console output and PhantomJS will
self.exit(); // terminate
},
onStepTimeout:function(self,m){
console.log('timeout:step ' + nextpageUrl_relative);
}
});
stepTimeout:超时毫秒数
verbose:字面意思是‘冗余的,如果设置为true,则log信息会打印在终端(控制台)。
onError:遇到错误是执行的方法。
onStepTimeout:这个比较有用,因为网络不好是经常会发生而且必须要考虑的问题。如果timeout了,可能有两个原因,1网络超时,2代码执行超时(如死循环)。如果是前者导致页面内容抓取失败则需要重试。一个方法是:把这个页面的url写到一个一个文本里面,然后在任务的最后把那些失败的url读进来重新访问网络,直到所有的页面都纳入囊中为止。
开始运行。
casper.start(realUrl,function(){
this.echo(realUrl+ ‘start.’);
});
因为一般一个网站都是大规模的,至少不是一页可以显示的,比较常见的一个需求是:读取一页,翻一页,如此循环直到最后一页。我们可以用casperjs提供的repeat方法。
casper.repeat(500,function() {
//catchcontent code
varnextPageButton = 'li.pagearrowright a';
this.echo(this.getElementAttribute(nextPageButton,'href'));
if(this.exists(nextPageButton)) {
this.waitFor(function(){return this.click(nextPageButton);});
}else { this.exit();}
this.wait(2000);
});
解释:casper.repeat(500,function(),之所以设置成500,是因为我知道那个网站的那些内容不会超过500页的,如果网站的内容只有400页,那也没事,有方法可以跳出循环提早结束。
casperjs是一个所谓的headlessbrowser,无头的浏览器,有人的解释是:没有界面的浏览器。虽然我们看不到,但是html内容都是实实在在的在那里,(其实也可以看到,capture()捕获屏幕)。所以用casperjs来收集信息的一个好处是,可以欺骗过很多网站,(有的网站是禁止爬虫的)。听说腾讯有的模块检测鼠标的移动轨迹来判断是否是真正的用户而不是机器人,那可能就露馅了。回到正题,既然casperjs是个浏览器,页面内容也是真正的存在,那么如果存在‘下一页’这个按钮或者超链接,则我们也是可以‘点击’那个按钮的:方法this.click(nextPageButton);这样我们就点击了一个按钮。点击之后需要等一会才能有结果。等多久呢?不用关心,它会好了之后通知我们:this.waitFor(function(){return this.click(nextPageButton);});
nextPageButton是一个selector,用来指明页面上的某个特定的元素。casperjs支持XPath和css3的selector的语法。
selector简单的例子:
html内容:
<html>
<head>
</head>
<body>
<ahref='a.html' target='_blank'>aaaaa</a>
<ahref='b.html' target='_blank'>bbbbb</a>
<divclass="qiuzu">
<li>aha</li>
<li>hello</li>
</div>
</body>
</html>
第一个超链接的selector'a'
第二个超链接的selector'a:nth-of-type(2)'
aha的selector:'div.qiuzuli'
hello的selector:'div.qiuzuli:nth-of-type(2)'
大概是这样子。
如果要打印第一个超链接的url‘a.html’,则可以这样
this.echo(this.getElementAttribute('a','href'));
如果要打印‘hello’,则可以这样
this.echo(this.getHTML('div.qiuzuli:nth-of-type(2)', 'href'));
要注意的一点是,如果原页面存在错误的话,可能会导致casperjs解析出现问题。
结尾记得加上一行:casper.run();
另外还可以截取casperjs发送到服务器的request,也可以截取服务器返回的response,但是服务器返回的response内容很少,是没有body的。这时我们可以迂回地处理这个问题。
1先截取casperjs发送到服务器的request的url
2用该url再次向服务器请求内容,这样就可以得到全部的服务器返回的信息了。