PhantomJS は、公式サイトで以下のように説明されています。
PhantomJS is a headless WebKit with JavaScript API. It has fast and native support for various web standards: DOM handling, CSS selector, JSON, Canvas, and SVG.
PhantomJS - Scriptable Headless Browser
PhantomJS: Headless WebKit with JavaScript API
これだと良く分からないんですけど、一言で言えば人間に見えるインタフェースがないままブラウジングができる、みたいなソフトウェアです。
誤解を恐れずに言えば、ブラウザ(Webkit)をスクリプトから操作できると言えばいいんでしょうか。ブラウザですから、アクセスしたページの DOM 構造も当然分かりますし、読み込まれている JavaScript も当然実行されます。
でまぁ、簡単なサンプルプログラムは phantomjs/examples at master · ariya/phantomjs · GitHub に公開されていて、JSONP が余裕でできたりとか、wikipedia にアクセスして余裕で PDF 化できたりする。
まぁでも画面遷移はできないと使えないし、ログインとかもできないと使いづらいから、サンプルプログラムつくったら良くわからない動作した。
#!/usr/local/bin/phantomjs --cookies-file=./cookie2.txt var page = require('webpage').create(), cnt = 0; page.onConsoleMessage = function (msg, lineNum, sourceId) { console.log(msg); }; page.customHeaders = { "User-Agent": 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.75 Safari/535.7', }; function login(username, password) { console.log("login starts."); page.open('https://www.hatena.ne.jp/login', function (status) { page.render("login.png"); page.evaluate( function (page, username, password, cnt) { console.log("try login: [" + cnt + "] " + username); // page.onLoadFinished = function (status) { // page.render('test.png'); // console.log("login complete"); // phantom.exit(); // }; document.getElementById('login-name').value = username; document.querySelector('input.password').value = password; document.querySelector('form').submit(); }, page, username, password, ++cnt ); }); } login('hatena id', 'pass);
で、これを実行すると、
% ./hatena.js [~/work/phantomjs] login starts. try login: [1] kiririmode try login: [2] kiririmode TypeError: 'null' is not an object (evaluating 'document.getElementById('login-name').value = username') phantomjs://webpage.evaluate():10 phantomjs://webpage.evaluate():14 phantomjs://webpage.evaluate():14 try login: [3] kiririmode TypeError: 'null' is not an object (evaluating 'document.getElementById('login-name').value = username') phantomjs://webpage.evaluate():10 phantomjs://webpage.evaluate():14 phantomjs://webpage.evaluate():14 try login: [4] kiririmode TypeError: 'null' is not an object (evaluating 'document.getElementById('login-name').value = username') phantomjs://webpage.evaluate():10 phantomjs://webpage.evaluate():14 phantomjs://webpage.evaluate():14
ななななんで try login 4 回も呼ばれちゃってんのーみたいな!意味わかんないみたいな!!!
ちなみに、try login 1 回目で既にログインはできていて、ログイン後のリダイレクト先に対して、page.open に与えている無名関数が再度呼ばれている動作をしている。
かんぜんに謎。よくわからん。こわい。
phantom.exit() 呼ぶタイミングの問題だと思うんだけど、いったいどのタイミングだったらええんや…。