官网http://casperjs.org/
分享http://download.csdn.net/detail/xiarendeniao/5781445
环境:
[dongsong@localhost ~]$ casperjs --version 1.0.0-RC2 [dongsong@localhost ~]$ phantomjs --version 1.7.0
提交表单可以通过fill直接完成(有些提交是js控制的,这种方法就行不通了)或者用click()点击提交按钮
下面给一个在evaluate内部做的例子(跟普通页面上的js编程类似)
// Querying for "Chuck Norris" on Google casper.start('http://google.fr/').thenEvaluate(function(term) { document.querySelector('input[name="q"]').setAttribute('value', term); document.querySelector('form[name="f"]').submit(); }, { term: 'Chuck Norris' }); casper.run();
再给个填没有name属性的input框框的例子:
casper.waitForSelector('#xx', function then() { recognizedCode = 'xxx'; this.evaluate(function(rtCode){ document.querySelector('input[class="xxx"]').value = rtCode; //1>可以用这种方式填input框框(without name attribute) //document.querySelector('a[action-type="submit"]')[0].click(); //2>可以在这里提交哦! //__utils__.findOne('input[class="WB_iptxt oauth_form_input oauth_form_code"]').value = rtCode; //1>也可以这样填input框框(without name attribute) }, {rtCode:recognizedCode}); this.click('a[action-type="submit"]'); //2>也可以在这里提交! }, function onTimeout() { this.log('wait selector timeout', 'error') }, timeout = 1000 );参考: https://groups.google.com/forum/#!msg/casperjs/iybL4kdLqVg/Exw8v2pcUXAJ
var casper = require("casper").create({ verbose: true, logLevel: "debug", onError: function(self,m){ this.capture("error.png"); console.log("FATAL:" + m); self.exit(); } });
还可以指定casper对象整个导航过程总的运行时间timeout,这样可以防止在程序因为网络原因或程序bug导致一直不退出,对应timeout的处理函数是onTimeout
与整个导航过程timeout和onTimeout相对应的是单步超时时间stepTimeout和单步超时处理函数onStepTimeout
require("utils").dump(xxx);
casperObj.cli.has(0) casperObj.cli.get(3) casperObj.cli.get('usename')
下面给个小例子
casper.on('resource.received', function(resource){ if (resource.redirectURL) { var rUrl = resource.redirectURL; if (rUrl.match(/\?code=(\w+)/g)) { code = rUrl.substr(rUrl.search(/\?code=(\w+)/g)+6); this.log("code=" + code,'info'); this.clear(); this.on('resource.received', function(resource) {}); } else return; } else return; });
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,要嘛飞快的死循环
//loop:隔一段时间就刷新一次简历(用waitFor和wait实现循环,貌似不靠谱儿!) /* casper.waitFor(function check(){ this.wait(10000, function() { this.click('a[title="简历刷新"]'); this.log('refreshed my resume'); } ); return false; }, function then() {}, function onTimeout() {this.log('timeout: refresh loop competed.', 'error');}, timeout = 120000 );*/
参考:https://github.com/n1k0/casperjs/blob/master/samples/dynamic.js
function refresh() { this.wait(10000, function() { this.click('a[title="简历刷新"]'); this.log('refreshed my resume'); } ); this.run(refresh); } 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~