我正在使用CasperJS通过网站自动执行一系列点击,完成表单,解析数据等。
Casper似乎被组织成then
语句形式的预设步骤列表(参见他们的示例:http://casperjs.org/quickstart.html)但是不清楚是什么触发了实际运行的下一个语句。
例如,then
是否等待所有待处理的请求完成? injectJS
是否会被视为待处理请求?如果我有一个嵌套的then
语句 - 链接到open
语句的末尾会发生什么?
casper.thenOpen('http://example.com/list', function(){
casper.page.injectJs('/libs/jquery.js');
casper.evaluate(function(){
var id = jQuery("span:contains('"+itemName+"')").closest("tr").find("input:first").val();
casper.open("http://example.com/show/"+id); //what if 'then' was added here?
});
});
casper.then(function(){
//parse the 'show' page
});
我正在寻找有关CasperJS中流程如何工作的技术说明。我的具体问题是我的then
语句(上图)在casper.open
语句之前运行。我不知道为什么。
答案 0 :(得分:93)
then()
基本上会在堆栈中添加新的导航步骤。步骤是一个javascript函数,可以做两件事:
我们来看一个简单的导航场景:
var casper = require('casper').create();
casper.start();
casper.then(function step1() {
this.echo('this is step one');
});
casper.then(function step2() {
this.echo('this is step two');
});
casper.thenOpen('http://google.com/', function step3() {
this.echo('this is step 3 (google.com is loaded)');
});
您可以打印出堆栈中所有已创建的步骤,如下所示:
require('utils').dump(casper.steps.map(function(step) {
return step.toString();
}));
这给出了:
$ casperjs test-steps.js
[
"function step1() { this.echo('this is step one'); }",
"function step2() { this.echo('this is step two'); }",
"function _step() { this.open(location, settings); }",
"function step3() { this.echo('this is step 3 (google.com is loaded)'); }"
]
注意CasperJS自动添加的_step()
函数为我们加载网址;当加载url时,将调用堆栈中可用的下一步 - 即step3()
。
定义导航步骤后,run()
会逐个执行导航步骤:
casper.run();
脚注:回调/监听器内容是Promise pattern的实现。
答案 1 :(得分:33)
then()
只是注册了一系列步骤。
run()
及其运行函数,回调和侦听器系列都是执行每一步的实际工作。
每当步骤完成时,CasperJS将检查3个标志:pendingWait
,loadInProgress
和navigationRequested
。如果这些标志中的任何一个为真,则不执行任何操作,直到稍后的时间(setInterval
样式)。如果这些标志都不为真,那么下一步将被执行。
从CasperJS 1.0.0-RC4开始,存在一个缺陷,在某些基于时间的情况下,在CasperJS有时间筹集其中任何一个之前,将触发“尝试下一步”方法。 1}}或loadInProgress
标志。解决方案是在离开任何希望引发这些标志的步骤之前引发其中一个标志(例如:在要求navigationRequested
之前或之后提出标志),也许是这样:
(注意:这只是说明性的,更像是psuedocode而不是正确的CasperJS形式......)
casper.click()
为了将该解决方案整理成一行代码,我在此github pull request中引入了step_one = function(){
casper.click(/* something */);
do_whatever_you_want()
casper.click(/* something else */); // Click something else, why not?
more_magic_that_you_like()
here_be_dragons()
// Raise a flag before exiting this "step"
profit()
}
,扩展了blockStep()
和click()
作为帮助保证的方法我们在使用clickLabel()
时得到了预期的行为。查看有关更多信息,使用模式和最低测试文件的请求。
答案 2 :(得分:0)
then()
签名: then(Function then)
此方法是通过提供一个简单功能将新的导航步骤添加到堆栈的标准方法:
casper.start('http://google.fr/');
casper.then(function() {
this.echo('I\'m in your google.');
});
casper.then(function() {
this.echo('Now, let me write something');
});
casper.then(function() {
this.echo('Oh well.');
});
casper.run();
您可以根据需要添加任意多个步骤。请注意,当前的
Casper
实例会自动在步骤函数中为您绑定this
关键字。要运行您定义的所有步骤,请调用
run()
方法,然后瞧瞧。注意:您必须
start()
Casper实例才能使用then()
方法。警告::在两种不同情况下处理添加到
then()
的步进函数:
- 执行上一步功能后,
- 先前的主要HTTP请求已执行并且页面已加载;
请注意,没有页面加载的单一定义;是何时触发DOMReady事件?是“所有请求都已完成”吗?是“正在执行所有应用程序逻辑”吗?还是“所有元素都被渲染”?答案总是取决于上下文。因此,为什么鼓励您始终使用
waitFor()
系列方法来保持对实际期望的明确控制。一个常见的技巧是使用
waitForSelector()
:
casper.start('http://my.website.com/');
casper.waitForSelector('#plop', function() {
this.echo('I\'m sure #plop is available in the DOM');
});
casper.run();
幕后的source code for Casper.prototype.then
如下所示:
/**
* Schedules the next step in the navigation process.
*
* @param function step A function to be called as a step
* @return Casper
*/
Casper.prototype.then = function then(step) {
"use strict";
this.checkStarted();
if (!utils.isFunction(step)) {
throw new CasperError("You can only define a step as a function");
}
// check if casper is running
if (this.checker === null) {
// append step to the end of the queue
step.level = 0;
this.steps.push(step);
} else {
// insert substep a level deeper
try {
step.level = this.steps[this.step - 1].level + 1;
} catch (e) {
step.level = 0;
}
var insertIndex = this.step;
while (this.steps[insertIndex] && step.level === this.steps[insertIndex].level) {
insertIndex++;
}
this.steps.splice(insertIndex, 0, step);
}
this.emit('step.added', step);
return this;
};
说明:
换句话说,then()
安排了导航过程的下一步。
在调用then()
时,会传递一个作为参数的函数,该函数将被称为步骤。
它检查实例是否已启动,如果尚未启动,则显示以下错误:
CasperError: Casper is not started, can't execute `then()`.
接下来,它将检查page
对象是否为null
。
如果条件为true,Casper将创建一个新的page
对象。
然后,then()
验证step
参数是否不是函数。
如果参数不是函数,则会显示以下错误:
CasperError: You can only define a step as a function
然后,该功能检查Casper是否正在运行。
如果Casper没有运行,则then()
将步骤附加到队列的末尾。
否则,如果Casper正在运行,它将插入比上一步更深的子步骤。
最后,then()
函数通过发出step.added
事件结束,并返回Casper对象。