RustからphantomJSを叩く

## 前置き
[PhantomJS](http://phantomjs.org/) は、バージョン1.8から、[GhostDriver](https://github.com/detro/ghostdriver) が取り込まれ、直接 [JsonWireProtocol](https://code.google.com/p/selenium/wiki/JsonWireProtocol)を叩く事が出来るようになりました。

このプロトコルはHTTPベースなので、[hyper](https://github.com/hyperium/hyper)で叩くだけで簡単に扱えます。

今回はそのアプローチで、RustからPhantomJSを叩いてみようと思います。

## PhantomJSをwebdriver有りで起動する
PhantomJSが、[JsonWireProtocol](https://code.google.com/p/selenium/wiki/JsonWireProtocol)を喋れるようにするには下記コマンドを実行します。

```bash
phantomjs --ignore-ssl-errors=yes --webdriver=8910
```
`ignore-ssl-errors` は、SSL証明書が検証できない場合において発生するエラーを無視するフラグですが、これは自由に設定して頂いて構いません。

`--webdriver=8910` で、phantomjsはサーバーとして起動し、ポート 8910 で待機します。

### webdriverについて補足
[Selenium Webdriver](http://www.seleniumhq.org/projects/webdriver/) というテストツールのことで、ブラウザテストを簡単に行えるツールです。
このツールでは[JsonWireProtocol](https://code.google.com/p/selenium/wiki/JsonWireProtocol) を話すことが出来る各Driver(Firefox Driver等さまざま)を経由し、テストを行います。しかし、FirefoxやChrome等は直接[JsonWireProtocol](https://code.google.com/p/selenium/wiki/JsonWireProtocol)を喋ることができないので、それぞれのDriverがありますが PhantomJSは内部にDriverを持っている(これがGhostDriver)ので、直接喋る事ができます。

`--webdriver`というパラメータなので、ややこしいですね。

## PhantomJSを叩く

今回も [サンプルコード](https://github.com/nacika-ins/ghostdriver_client) を用意しました。

```rust
extern crate ghostdriver_client;
extern crate cookie;
use cookie::Cookie as CookiePair;
use std::collections::BTreeMap;

fn main() {

    let mut phantomjs_session = ghostdriver_client::get_session("localhost".to_owned(),
                                                                "8910".to_owned(),
                                                                "Mozilla/5.0 (Macintosh; Intel \
                                                                 Mac OS X 10_11_0) \
                                                                 AppleWebKit/537.36 (KHTML, like \
                                                                 Gecko) Chrome/46.0.2490.80 \
                                                                 Safari/537.36"
                                                                    .to_owned());
    phantomjs_session.jump_to_url("http://google.com".to_owned());
    phantomjs_session.execute_script("document.body.style.backgroundColor = 'red'; return '1';"
                                         .to_owned());
    phantomjs_session.capture_screenshot("foo.png".to_owned());
    phantomjs_session.set_cookies(vec![CookiePair {
                                           name: "foo".to_owned(),
                                           value: "bar".to_owned(),
                                           expires: None,
                                           max_age: None,
                                           domain: None,
                                           path: None,
                                           secure: false,
                                           httponly: false,
                                           custom: BTreeMap::new(),
                                       }]);
    println!("{:?}", phantomjs_session.get_cookies());

}
```
Crate内部でやっていることは、hyperでHTTPを叩いているだけです。
まだ出来ることは限られていますが、メソッドを増やすことで他の機能も利用出来るようになります。

例えば、 [JsonWireProtocol](https://code.google.com/p/selenium/wiki/JsonWireProtocol) の
[session/:sessionId/element/:id/click](https://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/click) をラップしたメソッドを作ることで、DOM要素をクリックさせることも可能です。