casperjs小结

转自:http://blog.csdn.net/xiarendeniao/article/details/7740375


官网http://casperjs.org/

分享http://download.csdn.net/detail/xiarendeniao/5781445


环境:

[plain]  view plain copy
  1. [dongsong@localhost ~]$ casperjs --version  
  2. 1.0.0-RC2  
  3. [dongsong@localhost ~]$ phantomjs --version  
  4. 1.7.0  

1.casperjs按照start()、then*()、wait*()、open()等流程往下做导航(注意,如果有语法错误,比如少个分号神马的,可能运行时就无任何提示的卡那里了)
  run()方法触发该流程,run()方法可以指定一个onComplete()方法供导航完成时回调
  exit()/die()退出

2.打印html源码可以用debugHTML();打印web页面用debugPage();获取网页快照用capture('xx.png')

3.填写表单或者输入框用fill()做(要求文本框有name属性)或者在evaluate()内部做(evaluate相当于casperjs和网页之间的gate)

  提交表单可以通过fill直接完成(有些提交是js控制的,这种方法就行不通了)或者用click()点击提交按钮 

  下面给一个在evaluate内部做的例子(跟普通页面上的js编程类似)

[javascript]  view plain copy
  1. // Querying for "Chuck Norris" on Google  
  2. casper.start('http://google.fr/').thenEvaluate(function(term) {  
  3.     document.querySelector('input[name="q"]').setAttribute('value', term);  
  4.     document.querySelector('form[name="f"]').submit();  
  5. }, {  
  6.     term: 'Chuck Norris'  
  7. });  
  8.   
  9. casper.run();  

再给个填没有name属性的input框框的例子:

[javascript]  view plain copy
  1. casper.waitForSelector('#xx'function then() {  
  2.             recognizedCode = 'xxx';  
  3.             this.evaluate(function(rtCode){  
  4.                 document.querySelector('input[class="xxx"]').value = rtCode; //1>可以用这种方式填input框框(without name attribute)  
  5.                 //document.querySelector('a[action-type="submit"]')[0].click(); //2>可以在这里提交哦!  
  6.                 //__utils__.findOne('input[class="WB_iptxt oauth_form_input oauth_form_code"]').value = rtCode; //1>也可以这样填input框框(without name attribute)  
  7.             }, {rtCode:recognizedCode});  
  8.             this.click('a[action-type="submit"]'); //2>也可以在这里提交!  
  9.         },  
  10.         function onTimeout() {  
  11.             this.log('wait selector timeout''error')  
  12.         },  
  13.         timeout = 1000  
  14.     );  
参考: https://groups.google.com/forum/#!msg/casperjs/iybL4kdLqVg/Exw8v2pcUXAJ

4.日志console.log();或者由casperjs对象调用log()/echo()方法
  创建capserjs对象时可以指定日志级别、日志详尽程度、定制事件回调函数(OnError/onResourceReceived/httpStatusHandlers/...):
 
[javascript]  view plain copy
  1. var casper = require("casper").create({  
  2.         verbose: true,  
  3.         logLevel: "debug",  
  4.         onError: function(self,m){  
  5.                 this.capture("error.png");  
  6.                 console.log("FATAL:" + m);  
  7.                 self.exit();  
  8.             }  
  9.     });  

还可以指定casper对象整个导航过程总的运行时间timeout,这样可以防止在程序因为网络原因或程序bug导致一直不退出,对应timeout的处理函数是onTimeout

与整个导航过程timeout和onTimeout相对应的是单步超时时间stepTimeout和单步超时处理函数onStepTimeout

    
5.调试时免不了要打印变量或者对象的信息
[javascript]  view plain copy
  1. require("utils").dump(xxx);  

  
6.命令行参数由cli模块操作,详见 http://casperjs.org/cli.html
 
[javascript]  view plain copy
  1. casperObj.cli.has(0)  
  2. casperObj.cli.get(3)  
  3. casperObj.cli.get('usename')  

  
7.selector,跟css选择器规则一样(详见谷歌/度娘)
  #xx                 选取以xx为id的html标签
  xx[attr='value']    选取属性attr值为value的xx类型html标签
  .xx                选取以xx为class的html标签
  
8.事件,用casperObj.on()来注册事件的回调函数,详见 http://casperjs.org/events-filters.html
  要清除对某时间的监控和回调可以把回调函数设为空

  下面给个小例子

[javascript]  view plain copy
  1. casper.on('resource.received'function(resource){  
  2.         if (resource.redirectURL) {  
  3.             var rUrl = resource.redirectURL;  
  4.             if (rUrl.match(/\?code=(\w+)/g)) {  
  5.                 code = rUrl.substr(rUrl.search(/\?code=(\w+)/g)+6);  
  6.                 this.log("code=" + code,'info');  
  7.                 this.clear();  
  8.                 this.on('resource.received'function(resource) {});  
  9.             } else  
  10.                 return;  
  11.         } else  
  12.             return;  
  13.     });  

9.单纯的把timeout设置得很长,而不设置对应的超时函数,那么设置的这个值是不起作用的,可能是casperjs的bug,实践多次证明过这个问题

   比如,使用casperjsObj.waitForSelector()等待某个选择器时想定制timeout那么要提供onTimeout函数才行


10.实践证明一个casperjs程序内部无法创建多个casperjs对象

     那么如果需要同时访问多个站点、且需要用一个站点的某些数据填写另一个站点某个form、且form页面在重新请求时不一样(比如验证码,用back()倒回去验证码就不一样了),怎么办呢?

     鸟人的解决方案是自己提供一个页面内嵌两个frame分别装载目标站点;这里又有个问题是casperjs对象不能直接获取iframe内部的标签,需要用casperjsObj.page.switchToChildFrame(0/1/2)进入iframe、用casperjsObj.page.switchToParentFrame()回到上级iframe或者全局的位置(需要注意的是这两个函数和其他普通js程序一样、只有在导航过程中的某个function内部才有效,否则会被casperjs忽视,casperjs只认start/open/thenOpen/run/then/wait*/each/..等导航,普通js程序需要在这些导航对应的function内部填充)

 

11.capserjsObj.captureSelector()会有误差,可以根据casperjsObj.getElementBounds()获取要拍照的选择器的边界然后人工修订后把边界值传入casperjsObj.capture()拍照


12.控制导航跳向某一步、查看有多少步,可以用label/goto/dumpSteps函数,函数实现和用法详见https://github.com/yotsumoto/casperjs-goto


13.循环控制,我们不可避免的需要重复做一些动作,把所有的URL放到一个数组里面用each函数来处理当然不错,但是很有局限性,如果要重复的动作不是打开页面而是点击某个按钮呢?

鸟人想到的解决办法是用waitFor()+Wait()来实现循环,结果不太理想,要嘛卡死直到timeout,要嘛飞快的死循环

[plain]  view plain copy
  1. //loop:隔一段时间就刷新一次简历(用waitFor和wait实现循环,貌似不靠谱儿!)  
  2.         /*  
  3.         casper.waitFor(function check(){  
  4.                         this.wait(10000,  
  5.                                 function() {  
  6.                                         this.click('a[title="简历刷新"]');  
  7.                                         this.log('refreshed my resume');  
  8.                                 }  
  9.                         );  
  10.                         return false;  
  11.                 },  
  12.                 function then() {},  
  13.                 function onTimeout() {this.log('timeout: refresh loop competed.', 'error');},  
  14.                 timeout = 120000  
  15.         );*/  

网上寻来的解决方案是递归调用,casperjsObj调用run函数时可以传入一个结束时执行的函数,在这个函数里面可以加入【我们的循环体】和【递归的run调用】

参考:https://github.com/n1k0/casperjs/blob/master/samples/dynamic.js

[plain]  view plain copy
  1. function refresh()  
  2. {  
  3.         this.wait(10000,  
  4.                 function() {  
  5.                         this.click('a[title="简历刷新"]');  
  6.                         this.log('refreshed my resume');  
  7.                 }  
  8.         );  
  9.         this.run(refresh);  
  10. }  
  11. casper.run(refresh);  

14.日志中出现”Unsafe JavaScript attempt to access frame with URL”的info信息,启动casperjs时候加上参数--web-security=false(allow cross-domain XHR)即可(参见http://stackoverflow.com/questions/18960791/cant-run-a-basic-test-with-casperjs

要治本的话,参见http://stackoverflow.com/questions/4324108/unsafe-javascript-attempt-to-access-frame-with-url,who care~


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值