phantomjs page.evaluate から外のスコープの変数を参照する
信頼と実績の Stack Overflow でかいけつ
javascript - Pass arguments with page.evaluate - Stack Overflow
以下経緯
var page = require('webpage').create(); page.open("http://www.yahoo.co.jp/", function (status) { var selector = "title"; var value = page.evaluate(function () { return document.querySelector(selector).innerHTML; }); console.log(value); phantom.exit(); });
% phantomjs yahoo.js ReferenceError: Can't find variable: selector phantomjs://webpage.evaluate():2 phantomjs://webpage.evaluate():1 yahoo.js:4 null
selector
が参照できそうでできていない。document
は参照エラーになってないように、open したページ内のスコープしか参照できない。ぱっと見できそうだったから、なかなか理解できなかった。
evaluate(function)Evaluates the given function in the context of the web page. The execution is sandboxed, the web page has no access to the phantom object and it can't probe its own setting. Any return value must be of a simple object, i.e. no function or closure.
Interface - phantomjs - API Reference - headless WebKit with JavaScript API - Google Project Hosting
この問題について issue で議論されていて、参照させる変数を渡せる実装がコミットされているけどうまく参照できない... 使い方が違うんだろうか....
http://code.google.com/p/phantomjs/issues/detail?id=132
https://github.com/ariya/phantomjs/commit/81794f9096
var page = require('webpage').create(); page.open("http://www.yahoo.co.jp/", function (status) { var selector = "title"; var value = page.evaluate(function (s) { return document.querySelector(s).innerHTML; }, selector); console.log(value); phantom.exit(); });
% phantomjs yahoo.js TypeError: 'null' is not an object phantomjs://webpage.evaluate():2 phantomjs://webpage.evaluate():1 yahoo.js:4 null
というわけで Stack Overflow でかいけつできた。
javascript - Pass arguments with page.evaluate - Stack Overflow
var page = require('webpage').create(); page.open("http://www.yahoo.co.jp/", function (status) { var selector = "title"; var value = evaluate(page, function (s) { return document.querySelector(s).innerHTML; }, selector); console.log(value); phantom.exit(); }); /* * This function wraps WebPage.evaluate, and offers the possibility to pass * parameters into the webpage function. The PhantomJS issue is here: * * http://code.google.com/p/phantomjs/issues/detail?id=132 * * This is from comment #43. */ function evaluate(page, func) { var args = [].slice.call(arguments, 2); var fn = "function() { return (" + func.toString() + ").apply(this, " + JSON.stringify(args) + ");}"; return page.evaluate(fn); }
% phantomjs yahoo.js Yahoo! JAPAN
phantomjs-node
実際は phantomjs-node でこれをやりたかったので、上の evaluate を参考にした。
var phantom = require("phantom"); phantom.create(function (ph) { ph.createPage(function (page) { page.open("http://www.yahoo.co.jp/", function (status) { var selector = "title"; page.evaluate((function () { var func = function (s) { return document.querySelector(s).innerHTML; }; return "function() { return (" + func.toString() + ").apply(this, " + JSON.stringify([selector]) + ");}"; }()), function (value) { console.log(value); ph.exit(); }); }); }); });
% node phantom_yahoo.js Yahoo! JAPAN