私はPhantomJS page.evaluate()を使用してスクレイピングを行っています。私の問題は、Webkitページに渡すコードがサンドボックス化されているため、メインのファントムスクリプトの変数にアクセスできないことです。これにより、スクレイピングコードを汎用化することが難しくなります。
page.open(url, function() {
var foo = 42;
page.evaluate(function() {
// this code has no access to foo
console.log(foo);
});
}
引数をページにプッシュするにはどうすればよいですか?
まさにその問題がありました。 _page.evaluate
_も文字列を受け入れることができるため、ちょっとしたトリックで行うことができます。
いくつかの方法がありますが、evaluate
と呼ばれるラッパーを使用します。このラッパーは、Webkit側で評価する必要がある関数に渡す追加のパラメーターを受け入れます。次のように使用します。
_page.open(url, function() {
var foo = 42;
evaluate(page, function(foo) {
// this code has now has access to foo
console.log(foo);
}, foo);
});
_
そして、これはevaluate()
関数です:
_/*
* 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);
}
_
変更はプッシュされており、次のように使用できます。
page.open(url, function() {
var foo = 42;
page.evaluate( function(foo) {
// this code has now has access to foo
console.log(foo);
}, foo);
}
プッシュの詳細はこちら: https://github.com/ariya/phantomjs/commit/81794f9096
PhantomJS 0.9.2および0.2.0で動作するソリューションがあります。
page.evaluate(
function (aa, bb) { document.title = aa + "/" + bb;}, //the function
function (result) {}, // a callback when it's done
"aaa", //attr 1
"bbb"); //attr 2
引数をpage.evaluateの引数として関数に渡すことができます。
例:
page.evaluate(function(arg1, arg2){
console.log(arg1); //Will print "hi"
console.log(arg2); //Will print "there"
}, "hi", "there");
別の可能性:URLで変数を渡します。たとえば、オブジェクトxを渡すには
// turn your object "x" into a JSON string
var x_json = JSON.stringify(x);
// add to existing url
// you might want to check for existing "?" and add with "&"
url += '?' + encodeURIComponent(x_json);
page.open(url, function(status){
page.evaluate(function(){
// retrieve your var from document URL - if added with "&" this needs to change
var x_json = decodeURIComponent(window.location.search.substring(1));
// evil or not - eval is handy here
var x = eval('(' + x_json + ')');
)}
});
これは私のために働く:
page.evaluate("function() {document.body.innerHTML = '" + size + uid + "'}");
すべてを文字列として配置することを意味します。とにかくそれは文字列になります。ライブラリのソースを確認してください。
引数を関数にバインドすることはできませんか?
page.evaluate.bind(args)(callbackFn)
evaluate(function、arg1、arg2、...) に引数を渡すことができますが、これはしばしば少し面倒です。特に、いくつかの変数またはさらに悪いことに関数を渡す場合。
この障害を回避するには、代わりに injectJs(filename) を使用できます。
page.open(url, function() {
if ( webpage.injectJs('my_extra_functionality.js') ) {
page.evaluate( function() {
// this code has access to foo and also myFunction();
console.log(foo);
console.log(myFunction());
});
}
else {
console.log("Failed to inject JS");
}
}
どこmy_extra_functionality.js
は、同じディレクトリ内のローカルファイルです。
var foo = 42;
var myFunction = function(){
return "Hello world!";
}