初心者としてCasperJSで迷ったこと、困ったこと(2)
初心者としてCasperJSで迷ったこと、困ったこと - Itsukaraの日記の続きです。CasperJSのpage DOM環境からCasperJS環境に、任意のスクリプトを渡して実行する機能を試作しました。ご参考まで。(通常は(下図参照)、CasperJS環境からpage DOM環境にスクリプトを渡して実行するので、その逆となります)
背景
通常、page DOM環境からreturn文でデータを返せば、これがevaluate()の値になるので、これをCasperJS環境でファイルに書き込めば、page DOM環境で作成したデータをファイルに書き込めます。
しかし、page DOM環境内のスクリプトでsetTimeoutを使った処理をしたい場合は、このようなことができません。詳細は、前の記事「初心者としてCasperJSで迷ったこと、困ったこと - Itsukaraの日記」を参照ください。
また、page DOM環境では、Node.jsやCasperJSのfsが使えません。
そのため、page DOM環境で作成したデータをファイルに直接出力することができません。
page DOM環境でのファイル出力
CasperJSのAPIを少し調べたところ、page DOM環境からCasperJS環境へのコールバックができることが分かりました。そこで、これを利用すれば、page DOM環境のデータをCasperJS環境に渡し、CasperJS環境でデータをファイルに書き込むことができます。例えば、下記のようになります。
var casper = require("casper").create(); casper.on('remote.callback', function(data) { var fs = require("fs"); var fname = data.fname; var text = data.text; fs.write(fname, text); }); casper.start("https://en.wikipedia.org/wiki/Test", function() { casper.evaluate(function() { window.callPhantom({ fname: "test.txt", text : document.body.outerHTML }); }); casper.wait(2000); }); casper.run();
page DOM環境からCasperJS環境へのリモート実行
上記を一般化して、page DOM環境からCasperJS環境へのリモート実行機能を試作しました。window.callPhantom()の呼び出しでは、CasperJS環境で実行するスクリプトと、そのスクリプトで使うデータの2つを組み合わせたObjectを引数にしています。これによって、page DOM環境で作成したデータに対して、任意のスクリプトをCasperJS環境で実行できます。ご参考まで。
var casper = require("casper").create(); // デバッグ用の各種イベント登録 casper.on('remote.alert', function(msg) { this.echo("REMOTE.ALERT: " + msg); }); casper.on('remote.message', function(msg) { this.echo("REMOTE.MESSAGE: " + msg); }); casper.on("page.error", function(msg, trace) { this.echo("PAGE.ERROR: " + msg); this.echo("TRACE:"); for (var i = 0; i < trace.length; i++) { var trec = trace[i]; this.echo("file: " + trec.file + " , line: " + trec.line + " , function: " + trec.function); } this.die("TRACE END and die"); }); casper.on('step.error', function(err) { this.die("STEP.ERROR: " + err); }); casper.on("run.start", function() { casper.echo("CASPER RUN.START") }); casper.on("run.complete", function() { casper.echo("CASPER RUN.COMPLETE") }); // page DOM環境から渡されたスクリプトの実行 // // page DOM環境から渡されたデータは、「remARGS」で参照可能 // casper.on('remote.callback', function(data) { this.echo("REMOTE.CALLBACK:"); // this.echo(JSON.stringify(data)); var command = data.command; var remARGS = data.remARGS; this.echo("REMOTE.CALLBACK: <command is as follows>"); this.echo(command); // this.echo("<remARGS is as follows>"); // this.echo(JSON.stringify(remARGS)); eval(command); this.echo("REMOTE.CALLBACK END"); }); casper.start("https://en.wikipedia.org/wiki/Test", function() { casper.echo("POINT 1"); casper.evaluate(function() { // 以下のスクリプトは、page DOM環境で実行される var i = 0; f1(); function f1() { console.log("f1(): i = " + i); if (++i < 6) { setTimeout(f1, 1000); } else { console.log("f1(): FINISHED"); // PhantomJS+CasperJS環境で実行するコマンド var command = "var fs = require('fs');\n" + "fs.write('test.txt', " + "remARGS[0]" + ");\n" + "casper.die('FINISHED and DIE');\n"; // PhantomJS+CasperJS環境に渡すデータ var remARGS = [document.body.outerHTML]; window.callPhantom({ command: command, remARGS: remARGS }); } } }); // 下記により、evaluate()が完了するまで待つ casper.wait(20000); }); casper.run();
参考までに、上記の実行結果は下記です。
CASPER RUN.START POINT 1 REMOTE.MESSAGE: f1(): i = 0 REMOTE.MESSAGE: f1(): i = 1 REMOTE.MESSAGE: f1(): i = 2 REMOTE.MESSAGE: f1(): i = 3 REMOTE.MESSAGE: f1(): i = 4 REMOTE.MESSAGE: f1(): i = 5 REMOTE.MESSAGE: f1(): FINISHED REMOTE.CALLBACK: REMOTE.CALLBACK: <command is as follows> var fs = require('fs'); fs.write('test.txt', remARGS[0]); casper.die('FINISHED and DIE'); FINISHED and DIE REMOTE.CALLBACK END