phantomjsでfacebookに近況を投稿してみよう

こんにちは、SEの孟です。

今日のブログネタはphantomjsにしたいと思います。
http://phantomjs.org/

phantomjsはヘッドレスのwebkitツールで、コマンドラインから普通のブラウザと変わらない挙動でjavascriptapicss,domなどを利用することができます。
またjqueryをinjectJSして利用したり、サイトのスクリーンショットを取得することもできます。

phantomjsはクローラやjavascriptのテストツールとして多く使われているそうです。

ちなみに、インストールは簡単です。(この記事書いた時点での最新版は1.8.1です)
http://phantomjs.org/download.html

まずは、インストールに必要なライブラリを入れておきましょう。
gothicとminchoのフォントを入れておかないと文字化けします。
# yum install freetype-devel fontconfig-devel ipa-gothic-fonts ipa-mincho-fonts -y
# cd phantomjs-1.8.1-linux-x86_64
# cp bin/phantomjs /usr/local/bin
これで、インストール完了!

さて、使って見ましょう。

まずはFacebookスクリーンショット画像を作ってみたいと思います。
# vim facebook.phantomjs #拡張子はなんでもいいです
var page = require("webpage").create();
page.open("http://facebook.com",function(){
    page.render("/tmp/facebook_login.png");
    phantom.exit();
})
こんな感じです。まぁ、javascriptなので分かりやすいですよね。
phantomjsのコードは、ほとんどがコールバックの非同期方式です。最初はちょっと慣れないかもしれません。

では、これを実行してみます
 
# phantomjs facebook.phantomjs

お!/tmpの下に画像が生成されました!facebook_login.pngを開いてみましょう!

facebook_login

続きまして、Facebookにログインしてみたいと思います。
 
Facebookのログインフォームのエレメントにはそれぞれidが指定してあるので、document.querySelectorで値を入れてformをsubmitする感じにしたいと思います。この一連のdom操作にはpage.evaluateを使います。
そして、先ほどのスクリーンショットは、ログイン後に作るようにonLoadFinishedを使います。
var username = "blogphantomjs20130207@sute.jp";
var password = "hogehoge"

var page = require("webpage").create();
page.open("http://facebook.com",function(){
    page.onLoadFinished=function(){
        page.render("/tmp/facebook_home.png");
        phantom.exit();
    }
    page.evaluate(function(arr){
        document.querySelector("#email").value=arr[0];
        document.querySelector("#pass").value=arr[1];
        document.querySelector("#login_form").submit();
    },[username,password]);
})
※ page.evaluateの中から、外の変数を利用することできません。使いたい変数をevaluateの引数に渡せばOKです
※ evaluateのcallbackからreturnされた返り値はevaluateの返り値として受け取れます。var hoge = page.evaluate(...

実行してみると... はい!ログインできました。スクリーンショットも取れています。

facebook_home

最後に、近況を投稿してみましょう!
 
このブログのために、アカウントを作ったばかりなので、友達がいません!
プロファイルページに行ってから書くしかないですね...
var username = "blogphantomjs20130207@sute.jp";
var password = "hogehoge"

var page = require("webpage").create();
page.open("http://facebook.com",function(){
    // step 2
    page.onLoadFinished=function(){

        // step 4
        page.onLoadFinished = function(){

            // step 6
            page.onLoadFinished = function(){}

            // step 5
            page.evaluate(function(){
                document.querySelector("textarea").value="hello world!!! sent by phantomjs.";
                document.querySelector("form[action*=updatestatus]").submit();
            })

            // step 7
            window.setTimeout(function(){
                page.render("/tmp/facebook_result.png");
                phantom.exit();
            },3000);
        }

        // step 3
        page.evaluate(function(){
            var link = document.querySelector("a[href*=profile]");
            location.href=link.href;
        });
    }
    // step 1
    page.evaluate(function(arr){
        document.querySelector("#email").value=arr[0];
        document.querySelector("#pass").value=arr[1];
        document.querySelector("#login_form").submit();
    },[username,password]);
})

step順にソースを読むと理解しやすいと思います。
  • step 1 ログイン情報をdomで入れてformをsubmitしてログイン
  • step 2 先にcallbackを書く必要があるので、formをsubmitする前に書き換え、ログイン後のロジックをここに入れる
  • step 3 profileリンクを探して、リダイレクトする
  • step 4 リダイレクトされた後のロジックはここです
  • step 5 近況を書く場所を探して、値を入れて投稿
  • step 6 投稿後のコールバックロジックはここです。Ajaxで投稿するため、コールバックが複数回発生します。このため、空にしておきます
  • step 7 一連の動作が終わるまでTimeoutで待ってからスナップショットを取ります
ということで、実行してみると...

facebook_result


はい、こんな感じですね。この通りhello worldがphantomjsから投稿されました。
皆さんもphantomjsを使ってみてください。