WEBスクレイピングを行うサービスを開発していた時の事でした。
これまでWEBスクレイピング作業は、Linuxサーバーにcron登録して、bashで実行していただけなので、特に意識していなかったんですが、PHPのexecでbashコマンドを叩いてあげればいい・・・程度に考えていたら、動作しない事態に遭遇!!!
最初は軽く考えていましたが、この現象を解決するまでの工程をお楽しみください。
問題点の追求
とにかく、nodejsコマンドは実行できているのは下記コマンドでわかった。
exec("node -v",$res);
echo join("\n",$res);
> v4.2.6
でも、console.logを書きまくって検証した結果、下記の箇所が動作していませんでした。
var spooky = new Spooky($options , function(err){
console.log("spooky play !!");
...
}
spooky関数が動いていませんね・・・でもなんで????
とりあえずググる
まずは、ググり単語がよくわからないので、「spookyjs php error」として見るが、Spookyjsはまだまだマイナーツールのため、全然ヒットしません。
代わりにcasperjsがヒットするのですが、どうやらcasperjsをphpのexecで実行するときに、似たような現象になるようです。
対応方法として、下記のコマンドをPHPに記述すると書かれていました。
putenv("PHANTOMJS_EXECUTABLE=/usr/local/bin/phantomjs");
phantomjsのパスをPHPの環境変数にセットしているのですが、文字列のphantomjsのパスは環境によって違うようなので、ちゃんと
コマンドで確認して登録してみました。
・・・でも、相変わらず・・・
どうやらこれではなかったようなので、引き続きググる作業。
試しにphpのexecを別のコマンド関数に切り替えてみたらどうだろう・・・
PHPはとにかくシステムコマンドを実行する関数が多彩に存在するので、それぞれによってレスポンスが変わる可能性があると淡い期待を持って実行!
ここを参考にしました。
http://d.hatena.ne.jp/pasela/20081217/exec
exec("/usr/bin/node.js" , $res);
echo join("\n" , $res);
$res = shell_exec("/usr/bin/node.js");
echo $res;
$res = system("/usr/bin/node.js");
echo $res;
passthru("/usr/bin/node.js" , $res);
echo $res;
結果はどれもNG・・・orz
execでシステムエラーをまとめて表示
ここにきて、他サイトでのexecには、コマンド指定の最後に"2>&1"が書かれている事に気がつきました。
これは、システムエラーなどの際に、それも文字列として返すという意味なのだそうですが、これまでのNGは、実行しても何もかえってこない事象だったのですが、このコマンドを入れると、エラーが明確になりました。
events.js:141
throw er; // Unhandled 'error' event
^
Error: spawn casperjs ENOENT
at exports._errnoException (util.js:870:11)
at Process.ChildProcess._handle.onexit (internal/child_process.js:178:32)
at onErrorNT (internal/child_process.js:344:16)
at nextTickCallbackWith2Args (node.js:441:9)
at process._tickCallback (node.js:355:17)
at Function.Module.runMain (module.js:444:11)
at startup (node.js:136:18)
at node.js:966:3
上記のようなエラーが出ちゃっていたんですね。
これでようやくググる文字列が明確になりました。
"Error: spawn casperjs ENOENT"と書かれているので、casperjsでエラーになっているのがよく分かります。
何かが生成されていないようなのでググってみたところ、spooky関数を実行する時のオプションはcasperjsのオプションになるのですが、ここに、casperjsの環境変数パスを通すという作業が必要だったようです。
child: {
command : '/usr/local/bin/casperjs',
transport : 'stdio'
},
casper: {
logLevel : 'info',
verbose : true,
waitTimeout : 3000
}
先ほどのphantomjsと同じく、casperjsも
$ which casperjs
で調査して、フルパスを記載してあげました。
でもまだエラー・・・しかしエラー内容が変わりました。
events.js:141
throw er; // Unhandled 'error' event
^
Error: Child terminated with non-zero exit code 1
at Spooky.<anonymous> (/var/www/html/instagram/node_modules/spooky/lib/spooky.js:210:17)
at emitTwo (events.js:87:13)
at ChildProcess.emit (events.js:172:7)
at Process.ChildProcess._handle.onexit (internal/child_process.js:200:12)
なんとなくエラー文が短くなっていて、ゴールが近づいた感じがしました。
このエラーメッセージで検索すると、英語以外でも海外で同じ事象の方が掲示板で答えを求めていました。
日本語での解説ページはありませんでしたね。
オレ1番目かも( ̄▽ ̄)
ついに解決!!
どれも、casperjsのcommand値について書かれていましたが、ここで思いついたように、これまで修正内容を振り返っていたときに、phantomjsとcasperjsの両方を修正したモノで実行して見ると、なんと解決!!
どうやら、下記2点が必要だったようですね。
1. PHPにphantomjsの環境変数を設定
putenv("PHANTOMJS_EXECUTABLE=/usr/local/bin/phantomjs");
2. nodejsのspookyjs起動時に、casperjsの環境変数を指定
child内に以下を追加
"command : '/usr/local/bin/casperjs'"
この設定ができていれば、exec , system , shell_exec...どれを使ってもちゃんと動作するようになりました。
この辺はお好みでどうぞ。僕はexecが扱いやすいので、これを使い続けていますが・・・
あと、コマンドエラーをいち早く見つけるために、"2<&1"オプションは入れ込んでおくといいでしょう。
※本番では外してもいいですが・・・
そんなわけで、3時間ほど奮闘した備忘録になります。
この記事が、他の人の手助けになると幸いです。
0 件のコメント:
コメントを投稿