CasperJSで「その後」はどういう意味ですか


97

CasperJSを使用して、一連のクリック、完成したフォーム、データの解析などをWebサイトで自動化しています。

キャスパーは、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ステートメントの前に実行され、その理由がわかりません。


1
flowcasperjs の一般的な説明はまだ探していますが、基本的にevaluate呼び出し内からcasperjsを参照できないことを発見しました。(つまり、新しいURL、ログ、エコーなどを開くことはできません)。したがって、私の場合、evaluateが呼び出されていましたが、外部の世界と対話する方法がありませんでした。
bendytree 2012

1
私はまったく同じことを考えていましたが、尋ねるのが面倒です。良い質問!
ネイサン

4
evaluate()phantomjsが参照しているページのDOMで、「ブラウザー」で実行されるコード用です。したがって、そこにはありませんcasper.openが、jQueryが存在する可能性があります。だからあなたの例は意味がありませんが、私はまだthen()実際に何をするのか疑問に思います。
ネイサン

回答:


93

then()基本的に、スタックに新しいナビゲーションステップを追加します。ステップは、2つの異なることを実行できるJavaScript関数です。

  1. 前のステップを待っている-もしあれば-実行される
  2. リクエストされたURLと関連ページの読み込みを待機しています

簡単なナビゲーションのシナリオを見てみましょう:

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)'); }"
]

_step()CasperJSによってURLをロードするために自動的に追加された関数に注意してください。URLが読み込まれると、スタックで使用可能な次のステップ(つまり)step3()が呼び出されます。

ナビゲーションステップを定義したら、run()それらを1つずつ順番に実行します。

casper.run();

脚注:コールバック/リスナーのものは、Promiseパターンの実装です。


casperjs 1.0.0-RC1では、「test-steps.js」は、関数定義文字列のコレクションではなく、[オブジェクトDOMWindow]のコレクションを表示しています。
スターロック

[object DOMWindow]コレクションは、引き続き1.0.0-RC4の結果です。私はそれらの関数の定義はどこに行った...不思議
starlocke

1
最初は、CasperJSが関数をDOMWindowsに変換する新しいトリックを実行していると思っていましたが、問題は「return this.toString()」と「return step.toString()」でした-回答の編集を送信しました。
starlocke

5
いわゆる「スタック」は実際にはキューではありませんか?ステップは順番に実行されますが、それがスタックだったとしたら、ステップ3、ステップ2、ステップ1は期待できませんか?
Reut Sharabani 2013年

1
私はそれはこのようなものでなければならないと思います:あなたはステップのスタックを持っています。ステップをポップして評価します。空のキューを作成します。現在のステップの処理により生成されたステップは、このキューに入れられます。ステップの評価が完了すると、キュー内で生成されたすべてのステップがスタックの一番上に配置されますが、キュー内の順序は保持されます。(逆の順序でスタックにプッシュするのと同じです)。
マーク

33

then() 一連のステップを登録するだけです。

run() そしてそのランナー関数、コールバック、リスナーのファミリーはすべて、実際に各ステップを実行する作業を行うものです。

ステップが完了するたびに、CasperJSは、3つのフラグに対してチェックされますpendingWaitloadInProgressnavigationRequested。これらのフラグのいずれかがtrueの場合、何もせず、後でアイドルになる(setIntervalstyle)。これらのフラグのいずれも真でない場合、次のステップが実行されます。

CasperJS 1.0.0-RC4の時点で、特定の時間ベースの状況下で、「次のステップを実行する」メソッドが、CasperJSがloadInProgressまたはnavigationRequestedフラグのいずれかを上げる時間をとる前にトリガーされるという欠陥が存在します。解決策は、フラグが立てられると予想されるステップを離れる前に、これらのフラグの1つを立てることです(例:を要求する前または後にフラグを立てるcasper.click())。

(注:これは単なる例示であり、適切なCasperJSフォームよりも擬似コードに似ています...)

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()、このgithubのの中にプル要求拡張、click()およびclickLabel()使用するときに我々が期待される動作を取得することを助け保証するための手段としてthen()。詳細、使用パターン、最小テストファイルのリクエストを確認してください。


1
blockStepIMHO
Brian M. Huntの

「最終的な回答」の解決策についてはまだ話し合っています...「グローバルなデフォルト」の側面を実装したら、CasperJSがプルすることを願っています。
starlocke

1
ええ、それから目を離さないでください。:)
starlocke

これに対する解決策はありますか?はいの場合、それは何ですか?
Surender Singh Malik、2015

説明してくれてありがとう。Ajaxを多用するアプリケーションのCasper機能テストが常にランダムに失敗するため、この動作は1年以上私を殺しています。
brettjonesdev 2015

0

CasperJSドキュメントによると:

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インスタンスは、thisstep関数内でキーワードを自動的にバインドすることに注意してください。

定義したすべてのステップを実行するには、run()メソッドを呼び出してください。

注:このメソッドstart()を使用するには、キャスパーインスタンスが必要then()です。

警告:に追加されたステップ関数then()は、2つの異なるケースで処理されます。

  1. 前のステップ関数が実行されたとき、
  2. 前のメイン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();

舞台裏でのソースコードを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オブジェクトを返します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.