読者です 読者をやめる 読者になる 読者になる

無駄と文化

実用的ブログ

CentOS で node-webshot によるスクリーンショットの保存が出来ない問題への対処

Webサイトのスクリーンショットを保存してくれる便利なライブラリ node-webshot ですが、Ubuntu では問題なく動くコードが CentOSでは動かないという問題にぶち当たりました。
ドハマりして時間を食ったので解決策を記録しておきます。


結論

結論から書きます。
原因は node-webshot ではなく PhatnomJS 側でした、バージョン2.0の PhantomJS を使えば問題なくスクリーンショットを保存することができます。
PhantomJS v1.9.8 を使ってるとハマります。


症状

まずは問題のあったコードはこちら、

var webshot = require('webshot');

var options = {
  defaultWhiteBackground: true,

  // https 対応のための設定
  phantomConfig: {
    "ignore-ssl-errors": "true",
    "ssl-protocol": "any",
  },
};

var dirname  = process.argv[2];
var filename = process.argv[3];
var url      = process.argv[4];

var filepath = dirname + '/' + filename;

console.log('dirname: ', dirname);
console.log('filename: ', filename);
console.log('filepath: ', filepath);
console.log('url: ', url);

if (url) {
  // スクリーンショット保存
  webshot(url, filepath, options, function(err) {
    if (err) { console.log(err); }
  });
}

保存先の ディレクトリ名, ファイル名, 対象URL をコマンドライン引数で受け取って、そのとおりにスクリーンショットを保存するだけの簡単なコードです。

Ubuntu 14.04.3 LTS では問題なく動作するんですが、CentOS 6.7 では「終了コード 0 で正常終了するにも関わらず画像ファイルが保存されない」という問題が起きました。

エラーも起きず画像の保存だけがされないというのが厄介で、エラーメッセージも無いので解決の糸口が掴めません。


PhantomJS 単体で走らせると問題が発覚

node-webshot は単なる PhantomJS のラッパー です。
であれば PhantomJS 単体で動かしてみるか、とやってみて初めて問題点が見えてきました。

PhantomJS 公式サイトにあるサンプルプログラムをそのまま走らせてみた結果が以下の感じ。

$ phantomjs sample.js
PhantomJS has crashed.
Please read the crash reporting guide at https://github.com/ariya/phantomjs/wiki/Crash-Reporting
and file a bug report at https://github.com/ariya/phantomjs/issues/new
with the crash dump file attached: /tmp/556d4283-b6ec-f964-1f26fb63-64b9080d.dmp

はい、というわけで、「PhantomJS がクラッシュしてんぜ」とのことです。

クラッシュってどういうこと?と思いつつ Stack Overflow で検索すると、同じく CentOS で PhantomJS がクラッシュしてる方がチラホラ...。
回答を読んでみると、「PhantomJS のバグで、v2.0 なら修正されてるぜ」とのこと。

試しに、ココを参考にv2.0をインストールして、先ほどクラッシュしたサンプルコードを走らせると...。
正常に動く!

というわけで、PhantomJS v2.0 を使ってあげれば問題ないようです。


node-webshot で PhantomJS v2.0 を使う

node-webshot を使う理由の一つに「npm install webshot するだけで PhantomJS いい感じにインストールしてくれるから」というのがあるんですが。今回はそれが逆にネックになりますね。

最新版の node-webshot v0.17.0 のリポジトリを見ると、optionalDependencies が "phantomjs": "~1.9.7-1" となっています。
つまりは npm install wenshot しただけのプレーンな状態では PhantomJS v1.9.7 を使うことになるってことですね。

とはいえ対処策はあります。
オプションの phantomPath に外部の PhantomJS のパスを設定すれば、そっちを使ってくれるようになります。


先ほど別個にインストールした v2.0 が /usr/bin に入ったので、

var options = {
  defaultWhiteBackground: true,

  // https 対応のための設定
  phantomConfig: {
    "ignore-ssl-errors": "true",
    "ssl-protocol": "any",
  },

  // phantomjs の入っているパスに応じて設定する
  phantomPath: '/usr/bin/phantomjs',
};

ってな感じに書いておいてあげましょう。
これで node-webshot からも v2.0 の PhantomJS を使ってくれます。

実際に走らせてみると、問題なくスクリーンショットが保存されていることが確認できます。


まとめ

PhantomJS の公式サイトを見ても、『みんなどうせ OSX で使うよね?』的なノリで書かれているので嫌な予感はしたんですが。まさかOSによってはこんなでっかいバグが出るとは。

PhantomJS 関連の Stack Overflow を読むと「バージョン上げれば治るよ」と書かれているものも多いように見えますし、まだまだ安定度を見極めながら使っていかないと痛い目見るかもしれません。


最後に、CentOS でも正常に動くコードを貼っておきます。

var webshot = require('webshot');

var options = {
  defaultWhiteBackground: true,

  // https 対応のための設定
  phantomConfig: {
    "ignore-ssl-errors": "true",
    "ssl-protocol": "any",
  },

  // phantomjs の入っているパスに応じて設定する
  phantomPath: '/usr/bin/phantomjs',
};

var dirname  = process.argv[2];
var filename = process.argv[3];
var url      = process.argv[4];

var filepath = dirname + '/' + filename;

console.log('dirname: ', dirname);
console.log('filename: ', filename);
console.log('filepath: ', filepath);
console.log('url: ', url);

if (url) {
  // スクリーンショット保存
  webshot(url, filepath, options, function(err) {
    if (err) { console.log(err); }
  });
}

これでよし。


参考

qiita.com

github.com


私からは以上です。