いもろぐ

思い立ったら書いていくスタイルで

PhantomJS+CasperJSを使ってみる

(今回からMarkdown記法にしてみましたが読みにくい。うまいtipsがあったら教えて下さい)

久しく時間が空いてしまいましたが、この期間は Quickstart を見ながらCasperJSを使ってみようとしていました。

しかしながら私の基礎知識が足りないのでサンプルコードを見ながら一行進んでは調べて、、、を繰り返していました。(Casper以前に)わからなかったのは

  • Linuxの基本操作、permission設定。
  • そもそもエディタが使えない。ひとまず素のvi。syntaxの色分けとかできてない。vimrcをなんとかするらしいがうまくいかないのであとで調べる。★
  • vimとかemacsとかよくわかんないので Sublime text が非開発者にはフレンドリーっぽかったので使ってみようと思ったのですがWindowsからSSHで仮想環境のCentOSにつなぐ方法がわからなかったのであとで調べる。★
  • CSSでのセレクタ、プロパティ、値。

基礎知識って大事。そこで役になったのが ドットインストール。コンパクトに基礎を理解するにはとても参考になりました。CSSとDOM操作あたりを見ました。

■やったこと

1 http://docs.casperjs.org/en/latest/installation.html にしたがってPhantomJS、CasperJSをCentOSにインストールします。

2 http://docs.casperjs.org/en/latest/quickstart.html#a-minimal-scraping-script にある"A minimal scraping script"を丸写しして実行。URLを変更してみたりして実行。

ここまでは大丈夫。何をやってるのかも書いてあるので大丈夫。 そして、より本格的な(?)ブラウザ操作のサンプルコードに入ります。

http://docs.casperjs.org/en/latest/quickstart.html#now-let-s-scrape-google のサンプルコードを下記に転記します。

var links = [];
var casper = require('casper').create();

function getLinks() {
    var links = document.querySelectorAll('h3.r a');
    return Array.prototype.map.call(links, function(e) {
        return e.getAttribute('href');
    });
}

casper.start('http://google.fr/', function() {
    // search for 'casperjs' from google form
    this.fill('form[action="/search"]', { q: 'casperjs' }, true);
});

casper.then(function() {
    // aggregate results for the 'casperjs' search
    links = this.evaluate(getLinks);
    // now search for 'phantomjs' by filling the form again
    this.fill('form[action="/search"]', { q: 'phantomjs' }, true);
});

casper.then(function() {
    // aggregate results for the 'phantomjs' search
    links = links.concat(this.evaluate(getLinks));
});

casper.run(function() {
    // echo results in some pretty fashion
    this.echo(links.length + ' links found:');
    this.echo(' - ' + links.join('\n - ')).exit();
});

やってることは

1 http://google.fr/ にアクセスして検索ワードに'casperjs'を指定して検索を実行

2 検索結果をlinks配列に格納

3 続いて'phantomjs'を検索ワードに指定して検索実行

4 検索結果をlinks配列に追加

5 linksの中身を出力

だと思います。 サンプルコードなのでこのまま実行すれば動くのですが、私的にわからなかったところを1つずつ調べてみました。上から順番にいきます。


var links = [];
var casper = require('casper').create();

links配列を宣言して、casperjs始めるよってこと、、、だと思う。(インスタンスを作る?)


function getLinks() {
    var links = document.querySelectorAll('h3.r a');
    return Array.prototype.map.call(links, function(e) {
        return e.getAttribute('href');
    });
}
  • さっそく出てきた querySelectorAll って何?
document.querySelectorAll('h3.r a');

調べたところ、

  • javascriptの getElementByXxxx に替わる記法。
  • セレクタAPIは「CSSセレクタにマッチした要素を取得するためのメソッド」
  • CSSセレクタをキーにマッチした全てのノードをNodeListで取得
  • 'h3.r a' の意味は、「h3要素」で「rクラス」のものの子孫にある「a要素」を指定する
  • 該当したものをまるっと配列で返してくれる

とのこと。 実際の検索結果画面のHTMLが下記のようになっています。

<h3 class="r">
  <a href="/url?xxxxxxxxxx">

CSSでのセレクタについては http://dotinstall.com/lessons/basic_css/116 を参考にして理解しました。

/* セレクタを並べた時の意味 */
a, b /* aもbも */
a b  /* aの子孫要素のb */
a>b  /* aの子要素のb */
ab   /* a要素のうちbのもの */

ってことなので、サンプルコードの場合 'h3.r a' のrとaの間に半角スペースがあるので、h3の「子孫要素」にあたる a ってことですね。

return Array.prototype.map.call(links, function(e) {
    return e.getAttribute('href');
});
  • function(e)のeって何?

    • わかんなかった。あとで調べる。★
  • prototype属性って何?

  • mapメソッドって何?

    • http://keicode.com/jsref/array.map.php
    • Array の各要素を引数で指定したファンクションに渡し、その結果を要素とする新しい Array を返します。
    • links配列を渡すと、要素のそれぞれに対して function(e) を実行して、その結果を配列で返してくれるのね。
  • callメソッドって何?

    • http://taiju.hatenablog.com/entry/20100515/1273903873
    • この説明にある「主体と客体が逆になっている」あたりがこんがらがったけどわかった気がする
    • この場合、mapメソッドを所有しているのが Array.prototype で、mapメソッドを実行したい主体が links ってことね。(第二引数はmapに渡したい引数)
    • "document.getElementsByTagName('hoge')のように、DOMの要素リストを受け取った時に、見た目はArrayっぽいのにArrayのメソッドを持っていないという困った問題があります。こういう時、callメソッドが使えます。"とのこと。
  • getAttribute() って何?

    • 指定の要素について名前付けされた属性の値を返します。名前付けされた属性が存在しなければ、返される値は null もしくは ""(空文字列)となります
    • この場合は href="xxx" のxxxを返す

casper.start('http://google.fr/', function() {
    // search for 'casperjs' from google form
    this.fill('form[action="/search"]', { q: 'casperjs' }, true);
});

casper.then(function() {
    // aggregate results for the 'casperjs' search
    links = this.evaluate(getLinks);
    // now search for 'phantomjs' by filling the form again
    this.fill('form[action="/search"]', { q: 'phantomjs' }, true);
});
  • evaluateメソッドって何?
    • http://docs.casperjs.org/en/latest/modules/casper.html#evaluate
    • casperjsのメソッド
    • evaluateメソッドは「引数であるfunctionを、その時表示されているHTML(DOM)に挿入して実行し、その結果を取得する」という解釈でいいのかな?
    • 日本語でこのメソッドを解説しているページが見つからず、公式を見てみましたが、私の読解力ではこんな理解度、、、
    • (aggregate=集める、evaluate=評価する、査定するって意味なのねw)

casper.then(function() {
    // aggregate results for the 'phantomjs' search
    links = links.concat(this.evaluate(getLinks));
});
  • concatメソッドって何?
    • http://javascriptist.net/ref/Array.concat.html
    • javascriptのメソッド
    • Array.concat(arrya1,array2...) - 配列を連結した値を得る
    • サンプルでは 'casperjs' についての検索結果が links[] に入っているので、それに 'phantomjs' での検索結果を連結してくれる

casper.run(function() {
    // echo results in some pretty fashion
    this.echo(links.length + ' links found:');
    this.echo(' - ' + links.join('\n - ')).exit();
});
  • echoで出力する

...とここまで。
「使えるようになった」にはまだほど遠いですが、何をやっているのかはわかった気がする。
あとは自分でシナリオ作って、その通りに操作するプログラムをすればいいわけね。
http://docs.casperjs.org/en/latest/quickstart.html#a-minimal-testing-script にはtesting frameworkとしての使い方が書かれているので次回はここから試してみます。