【続】phantomjs/casperjsによるキャプチャー自動化

#はじめに
前回のエントリー[「phantomjs/casperjsによるキャプチャー自動化」](http://qiita.com/hika09/items/1944530465dea06749e6)で簡単なキャプチャースクリプトを製作しましたがサイトによって背景色が黒くなってしまったりと、課題や改修すべきところがありましたので前回のスクリプトをベースに改修していきたいと思います。
（環境構築は既に済んでいる前提です。）

#課題、改修点

**・サイトによっては背景が黒くなってしまう**
＞jqueryを読み込んで背景色を書き換えます。

**・キャプチャーするファイルリストを外部ファイル化（csvファイル読み込みも）**
＞jsonファイルの外部化だけだと簡単すぎるので、csvファイル読み込みのパターンも実装したいと思います。エクセルからキャプチャーリストを作成したり、website explorerからURLだけ引っ張ってきて連続キャプチャーしたりと使い勝手がよくなります。

**・キャプチャーした画像の保存先を変更したい**
＞rootディレクトリにキャプチャー用のディレクトリを生成して保存するように変更します。またキャプチャーファイルの上書きが発生しないようユニークな値（現在の日時）をディレクトリに指定する方法で実装します。

**・各デバイスごとのキャプチャー切り替えをコマンドラインから入力したい**
＞デバイスごとのキャプチャーをしたいときにコメントアウトを切り替えるのがめんどくさいのでコマンドラインから引数を渡しデバイス設定を切り替えたいと思います。

**・ベーシック認証をコマンドラインから入力したい**
＞こちらもコマンドラインから入力できるように変更したいと思います。正直この改修は使い勝手がよくなるか微妙ですが「コマンドラインからオプションも渡せる」という紹介程度で実装したいと思います。

#ディレクトリ構成、スクリプト
##ディレクトリ構成
今回は外部ファイルが複数あるのでディレクトリ構成は下記のとおりとなります。
キャプチャーディレクトリは自動で生成されるため不要です。

```
casperjs(root)
├listcap.js
├links.json
├links.csv
└lib
 └jquery-1.12.0.js
```

##キャプチャーURLリスト
今回はgoogleとyahoo!のサイトをキャプチャーしたいと思います。
このサイトを[前回のスクリプト](http://qiita.com/hika09/items/1944530465dea06749e6)でキャプチャーするとyahoo!のキャプチャーの背景色が黒くレンダリングされてしまいます。（phantomjsのデフォルト設定では透過でレンダリングされるため、background-colorを指定していないサイトでは黒くレンダリングされます↓↓こんな感じ）
![yahoo_cap.jpg](https://qiita-image-store.s3.amazonaws.com/0/30090/edfaf714-bb1e-9bb4-9263-9322be0e7afd.jpeg)

ですので今回の改修で背景色が白になっていれば成功です。!


```json:links.json
[
	["https://www.google.co.jp/","google.jpg"],
	["http://www.yahoo.co.jp/","yahoo.jpg"]
]
```
```links.csv
https://www.google.co.jp,google.jpg
http://www.yahoo.co.jp,yahoo.jpg

```

##スクリプト

```js:listcap.js
/**
 * Usage:
 * $ casperjs listcap.js sp --id=hoge --pass=fuga
 */
var casper = require('casper').create({clientScripts: ['./lib/jquery-1.12.0.js']});

/**
 * CSVファイル読み込み
 * jsonの場合下記に置き換え:
 *　var links = require('./links.json');
 */
var fs = require('fs');
var buffer = fs.read('./links.csv');
		buffer = buffer.replace( /\r\n/g , '\n' );
var links = convertArray(buffer);

/**
 * キャプチャー遅延処理
 */
var waitTime = 2000;

/**
 * ベーシック認証
 */
var basicId = casper.cli.options.id;
var basicPass = casper.cli.options.pass;

/**
 * 引数によるデバイスの切り替え（sp/tl）
 * デフォルトデバイスはpcに設定
 */
var device = String(casper.cli.args);
switch(device){
	case 'sp':
		var width = 320;
		var height = 568;
		var ua = 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_0_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12A405 Safari/600.1.4';
		break;
	case 'tl':
		var width = 768;
		var height = 1024;
		var ua = 'Mozilla/5.0 (iPad; CPU OS 8_0_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12A405 Safari/600.1.4';
		break;
	default:
		var width = 1280;
		var height = 900;
		var ua = 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.63 Safari/537.36';
		var device = 'pc';
		break;
}

/**
 * 現在の日時を取得
 * YYYYMMDD_HHMMSS
 */
var currentDate = new Date();
var currentDateTime = currentDate.getFullYear() + 
											alignNum(currentDate.getMonth() + 1) + 
											alignNum(currentDate.getDate()) +
											'_' + 
											alignNum(currentDate.getHours()) + 
											alignNum(currentDate.getMinutes()) + 
											alignNum(currentDate.getSeconds());

/**
 * 各ステータスの設定とループ設定
 */
casper.start();
casper.userAgent(ua);
casper.viewport(width, height);
casper.setHttpAuth(basicId, basicPass);

casper.each(
	links,
	function(self,link){
		var url =link[0];
		var file =link[1];

		self.thenOpen(url, function () {
			this.echo('captur page title:' + this.getTitle());
			casper.evaluate(function(){
				$('body').css('background-color','#fff');
			});
		});

		self.wait(waitTime,function(){
			self.capture(currentDateTime + device + '/' + file);
	});
});

/**
 * CasperJS実行
 */
casper.run();

function convertArray(buf){
	var csvList =[];
	var tmpList = buf.split('\n');
	for(var i = 0; i < tmpList.length; i++){
		var cells = tmpList[i].split(',');
		if(cells.length !=1){
			csvList.push(cells);
		}
	}
	return csvList;
}

function alignNum(num) {
  var r = String(num);
  if ( r.length === 1 ) {
    r = '0' + r;
  }
  return r;
}

```

#解説
##サイトによっては背景が黒くなってしまう
まずはclientScriptsにローカルのjqueryファイルを読み込ませます。

```
var casper = require('casper').create({clientScripts: ['./lib/jquery-1.12.0.js']});
```
これでjqueryを使用できるようになりました。
次にcasper.evaluateメソッドを使いwebページ内の変数やメソッドにアクセス。bodyの背景色を#fffに変更します。
これで背景色が指定されていないサイトでも白色でレンダリングされるようになります。

```
casper.evaluate(function(){
  $('body').css('background-color','#fff');
});
```


##キャプチャーするファイルリストを外部ファイル化（csvファイル読み込みも）
###json版
node.jsのrequireメソッドで外部ファイルを取得し変数に格納します。
たったこれだけです。

```
var links = require('./links.json');
```

###csv版
CSVの方がキャプチャーリストを作るうえでは楽そうなのでCSV読み込みを実装します。
`var fs = require('fs');` `var buffer = fs.read('./links.csv');`でまずはcsvファイルを読み込みます。
このときreplaceで改行コードを統一しておかないとwindowsではキャプチャーファイル名がうまく通らなくなります。（macは不要です）

```
var fs = require('fs');
var buffer = fs.read('./links.csv');
    buffer = buffer.replace( /\r\n/g , '\n' );
```
次に二次元配列に変換します。
まず`split('\n');`改行コードで分割し、`.split(',');`「,」でさらに分割する関数を実行します。

```
var links = convertArray(buffer);

function convertArray(buf){
	var csvList =[];
	var tmpList = buf.split('\n');
	for(var i = 0; i < tmpList.length; i++){
		var cells = tmpList[i].split(',');
		if(cells.length !=1){
			csvList.push(cells);
		}
	}
	return csvList;
}
```
これでcsvにも対応できるようになりました。



##キャプチャーした画像の保存先を変更したい
こちらもとてもシンプルです。
`self.capture(file);`の記述を`self.capture('hoge/' + file);`に変更すればhogeディレクトリを生成してキャプチャーが格納されます。
複雑な処理を記述しなくて良いのでめっちゃ便利です。

今回はディレクトリ名に現在の年月日時分秒を指定したいので`var currentDateTime`に現在の時間を格納しファイル名を連結させます。

```
elf.capture(currentDateTime + device + '/' + file);
```

ちなみに`device`は前述してしまいますが、デバイスの切り分けで使用する変数になります。
フォルダの判別しやすくなるので連結することにしました。


##各デバイスごとのキャプチャー切り替えをコマンドラインから入力したい
casperjsはコマンドを叩く際に引数を渡せます。
値の取得は`casper.cli.args`メソッドで取得でき、オブジェクトで返ってきます。
今回はswitch文で切り替えるため（型まで評価するため）`var device = String(casper.cli.args);`で型をStringに変えています。

あとはコメントアウトで切り替えていたデバイス設定をswitchに置き換えるだけです。

```
switch(device){
	case 'sp':
		var width = 320;
		var height = 568;
		var ua = 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_0_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12A405 Safari/600.1.4';
		break;
	case 'tl':
		var width = 768;
		var height = 1024;
		var ua = 'Mozilla/5.0 (iPad; CPU OS 8_0_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12A405 Safari/600.1.4';
		break;
	default:
		var width = 1280;
		var height = 900;
		var ua = 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.63 Safari/537.36';
		var device = 'pc';
		break;
}
```

これでデバイスごとのキャプチャーが行えるようになりました。
PC > `casperjs listcap.js`
スマホ > `casperjs listcap.js sp`
タブレット > `casperjs listcap.js tl`


##ベーシック認証をコマンドラインから入力したい

今回キャプチャーするサイトではベーシック認証をしようしませんが、ID,PASSをコマンドラインからオプションで渡してみたいと思います。
オプションの渡し方は2通りあり
`casperjs listcap.js --id`で`id=true`真偽値の設定
`casperjs listcap.js --id=hoge`で`id=hoge`文字列の設定
ですので今回は`--id=hoge`で実装します。

オプションの取得はcasper.cli.optionsメソッドで取得します。
ですので変数`basicId``basicPass`に代入すれば完成です。

```
var basicId = casper.cli.options.id;
var basicPass = casper.cli.options.pass;
```

個人的には、叩くコマンドが長くなるためベーシック認証のパスはソースコード内に記述したほうが使いやすいと感じてます。このあたりは使う人によるかもしれません。


#実行
実際にキャプチャーできるか実行してみます。
`casperjs listcap.js`
`casperjs listcap.js sp`
![yahoo.jpg](https://qiita-image-store.s3.amazonaws.com/0/30090/d7ec25fe-ee49-d999-eb47-16af663ed410.jpeg)

yahoo!の背景も白でレンダリングされております。SPのレンダリングも問題なさそうです。
（googleのレンダリング画像は省略させていただきました）

以上で終わりとなります。

次はmeta情報やaタグの内容をcsv出力するスクリプトを作ってみたいですね。
時間のかかるコンテンツデータチェックを効率化していきたいと思います。