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属性って何?
- http://www.dab.hi-ho.ne.jp/sasa/biboroku/javascript/prototype.html
- javascriptの属性。既に生成したインスタンスを含めて、そのクラスの属性。メソッドを追加できるって。
- ここに深入りすると戻ってこれなくなりそうだったのでこれくらいの認識で進めます。
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); });
- fillメソッドって何?
- http://docs.casperjs.org/en/latest/modules/casper.html#fill
- casperjsのメソッド
- 第一引数:セレクタ
- 第二引数:オブジェクトと入力したい値。ここのqは入力欄のname <input id="gbqfq" class="gbqfif" name="q" type="text"...
- 第三引数:submitするかしないか
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としての使い方が書かれているので次回はここから試してみます。