casperJsでブラウザ作業を自動化するまでの5つのステップ

# はじめに
前回書いた内容を知り合いに見せたら、「ピンポイントすぎてわからん」、「それ以前にハマる」、という声があったので、自分が踏んだステップとハマったポイントを再度まとめました。
で、それをソースで説明できるようにサンプルを作ったので、これをすればブラウザ作業の自動化のベースは作れると思います。（作れるはず）

**それなりに細かく書いたので思ったよりボリューミーです**

# step1：phantomJs, capserJsのインストール

```
sudo yum install nodes npm
sudo npm install -g phantomjs
sudo npm install -g casperjs
```

これだけ
あとはバージョンを確認できればOK （失敗例とその対策は後に書いてます）

```
phantomjs -v
2.1.1
casperjs --version
1.1.4
```

**ハマりポイント①　npm installで失敗**

```
npm install -g phantomjs
npm http GET https://registry.npmjs.org/phantomjs
npm http GET https://registry.npmjs.org/phantomjs
npm http GET https://registry.npmjs.org/phantomjs
npm ERR! Error: CERT_UNTRUSTED
```

こんな感じでインストールできなかったら、`npm config set strict-ssl false`を実行
※install完了後にtrueに戻すことを忘れずに

**ハマりポイント②　phantomjsが実行できない**

```
phantomjs -v
/usr/lib/node_modules/phantomjs/lib/phantom/bin/phantomjs: error while loading shared libraries: libfontconfig.so.1: cannot open shared object file: No such file or directory
```

こんなエラーがでたら、`sudo yum -y install fontconfig-devel `を実行
※[CentOSでPhantomJSの起動ができない](https://qiita.com/hondy12345/items/3900f6270b875b572836) を参考にしました

# step2：とりあえず簡単なものを実行してみる

サンプルとして「googleで検索して、その検索結果をキャプチャする」まで実施してみる
※ここまでは[CasperJSでブラウザ操作を自動化しよう](https://qiita.com/a-kane/items/a5d4b8345bc9c5d2c15c)を参考にしました

```javascript:sample.js
var casper = require('casper').create();
casper.start("https://www.google.co.jp/");
casper.then(function() {
  this.capture('google.png');
});
casper.run();
```

こんな感じでサンプルを作成
`start()`と`capture()`は直感的にわかると思うので割愛
`then()`はその処理が完了するまで待ってから引数に設定した関数を実行する
今回であれば、google.co.jpが表示されてから`this.capture('google.png')`を実行する
`run()`は処理の実行（これがないと、何もおきなくなります。）

モジュールができたのでこのコマンド（`casperjs sample.js`）を実行
すると、「google.png」ができていて、ちゃんとキャプチャされているはず。

次に、サンプルを少し変更して「casperjs」で検索かけて、キャプチャをとるように修正

```javascript:sample.js
var casper = require('casper').create();
casper.start("https://www.google.co.jp/");
casper.then(function() {
  this.capture('google.png');
}).then(function() {
  this.fill('form', {'q': 'casperjs'}, true);
});
casper.then(function() {
  this.capture('search_casperjs.png');
});
casper.run();
```

追加点としては、`capture()`でキャプチャとるのを待ってから、`fill()`を実行している部分
`fill()`は'form'に引数のjsonで指定したパラメータを設定しサブミットする
今回の処理では、formタグ内に、`<input name='q' ・・・`のvalueにcasperjsを設定している感じ
それで、最後に`true`を設定すればサブミットする。（falseなら値を入れるだけで終わる）

**ハマりポイント③**
ちなみに、`capture()`と`fill()`の間に`then()`を挟まないと正しい挙動にならない。
どうやら、`capture()`で画面をキャプチャしている途中だから、`fill()`による画面遷移が効いていない模様。
※調べたが具体的な原因はわからず。（知っている人がいたら教えてください）

# step３：submit以外の画面遷移（リンク押下）を対応する

サブミットだけじゃリンクが対応できん。ということでクリック操作のサンプルを作成
「qiitaで自分の記事を検索かけて、キャプチャする」ってものを作る
※ついでに、キャプチャを綺麗（サイズがおかしいのを対応）

```javascript:sample2.js
var casper = require('casper').create();
casper.start("https://qiita.com/");
casper.viewport(1280, 768);  // これで1280×768でキャプチャとる

casper.then(function() {
  this.fill('form', {'q': '"casperJsを使ってポップアップ画面でファイルアップロードするまで"'}, true);
});

casper.then(function() {
  this.capture('search.png');
}).then(function() {
  // 完全一致で検索かけているから１つのみだろうけど、念のためURLで自分の記事チェックを挟む
  this.click(".searchResult_main .searchResult_itemTitle a[href^='/192_60_33_2']");
});

casper.then(function() {
  this.capture('item.png');
});
casper.run();
```

前回から変わったことと言えば、
1.　`viewport()`でサイズ指定
2.　`click()`でクリック。クリックしたいseletorを指定してあげればOK

ただ、思った通りの挙動にならず。
どうやら、完全に描画される前にキャプチャを取ってたり、クリックイベントが動いている模様

**ハマりポイント④　サーバからのレスポンスをちゃんと待つ！**
ということで、描画されていることを待つために`waitForSelector()`を利用
これで対象のselectorが見つかるまで待てる。ということでサンプルに反映

```javascript:sample2.js
var casper = require('casper').create();
casper.start("https://qiita.com/");
casper.viewport(1280, 768);

casper.then(function() {
  this.fill('form', {'q': '"casperJsを使ってポップアップ画面でファイルアップロードするまで"'}, true);
});

casper.waitForSelector(".searchResult_main", function() {
  this.echo("complate search...");
}, function() {
  this.echo("timeout... wait 10s");
  this.exit();
}, 10000).then(function() {
  this.capture('search.png');
}).then(function() {
  this.click(".searchResult_main .searchResult_itemTitle a[href^='/192_60_33_2']");
});
casper.then(function() {
  this.capture('item.png');
});
casper.run();
```

`waitForSelector(待つ対象selector, Function 実行処理, [Function タイムアウト時の実行処理, タイムアウト時間(s)])`
となっているので、タイムアウトしなければメッセージ出して後続処理を実行、タイムアウトなら`exit()`で終了とする感じ（ちなみにデフォルトは5秒らしいです。）

# step4：form以外でパラメータを渡す

ここでやりたいのは、submitする必要がないけど、データ渡したいとき、ってありません？
例えば、「selectboxを選んだら、それに合わせてリンクが切り替わる。」的なものです。

```javascript:sample3
casper.then(function() {
  this.sendKeys('.selector', 'value', {reset: ture});
}).then(function() {
  this.click('.links a');
});
```

すみません、ちゃんとしたサンプルないのでイメージです。（いい例がなかったので）

今回やったことは、`sendKeys()`でデータを設定すること、対象のselectorに'value'を設定する感じ
`reset`がtrueなら上書き。falseなら追記

**ハマりポイント⑤　ajaxもサーバからのレスポンスをちゃんと待つ！**
ajax処理後のDOM操作内容によっては前の`waitForSelector()`では対応できないケースがある
例えば、`$('.selector').text('XXXX')`のような処理
こんな感じで遷移先だけ変えられた場合にselectorが増えないので対応しきれない（そんな無理やりやっているサイトがあるのです）

その対応として、`waitForSelectorTextChange()`を利用する
これにより、対象のselectorの中身が変わったら後続が動くようになる。

```javascript:sample3
casper.then(function() {
  this.sendKeys('.selector', 'value', {reset: ture});
}).waitForSelectorTextChange('.selector', function() {
    this.echo('.selector changed...');
}, function() {
  // タイムアウトは終了...
  this.echo("timeout... wait 10s");
  this.exit();
}, 10000).then(function() {
  this.click('.links a');
});
```

使い方は、`waitForSelector()`と変わらないので説明は割愛する

# step5：その他諸々もあるよね。（今後もふくめて）
### ブラウザの「戻る」「進む」も対応したい！
戻るはブラウザバックですけど、進むはなんて言うんですかね？ブラウザフォワード？
[こちら](http://docs.casperjs.org/en/latest/modules/casper.html#forward)を見れば一発かと。

### ポップアップ、iframeとかに対応したい！
ここでようやく前回の内容が登場
[casperJsを使ってポップアップ画面でファイルアップロードするまで](https://qiita.com/192_60_33_2/items/5102526e326439b8115c)

### ドラッグ＆ドロップも対応したい！
`mouseEvent()`で対応できそう
けど、試していないからまたの機会に。

# おわりに（感想）
これで、ブラウザ作業は一通り実施できると思います。
ここまで見てくれてありがとうございます。

正直、「まとめてると結構な量になってしまった、全部見てもらえるだろうか」という感想
初心者はこのぐらいあると嬉しいと思うが、この情報量がノイズになる人もいるのだろうな、と思うと難しい・・・

細かくアウトプットすれば、1つ１つはシンプルだけど、全体で流れができるからきっとそれがいいんだろうな、と思いました。
個人的な今回の学びは、技術的なことではなくて、アウトプットの仕方的な話でした