J'utilise page.evaluate () de PhantomJS pour effectuer des opérations de grattage. Mon problème est que le code que je passe à la page webkit est en mode bac à sable et n'a donc pas accès aux variables de mon script fantôme principal. Cela rend difficile de rendre générique le code de grattage.
page.open(url, function() {
var foo = 42;
page.evaluate(function() {
// this code has no access to foo
console.log(foo);
});
}
Comment pourrais-je pousser des arguments dans la page?
J'ai eu ce problème exact. Cela peut être fait avec un peu de ruse, parce que page.evaluate
peut aussi accepter une chaîne.
Il y a plusieurs façons de le faire, mais j'utilise un wrapper appelé evaluate
, qui accepte des paramètres supplémentaires à transmettre à la fonction devant être évaluée du côté du webkit. Vous l'utiliseriez comme ceci:
page.open(url, function() {
var foo = 42;
evaluate(page, function(foo) {
// this code has now has access to foo
console.log(foo);
}, foo);
});
Et voici la fonction 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);
}
Le changement a été poussé et vous pouvez maintenant l'utiliser comme
page.open(url, function() {
var foo = 42;
page.evaluate( function(foo) {
// this code has now has access to foo
console.log(foo);
}, foo);
}
Les détails Push sont ici: https://github.com/ariya/phantomjs/commit/81794f9096
Il y a la solution qui fonctionne avec PhantomJS 0.9.2 et 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
Une autre possibilité: passer les variables avec l'URL. Par exemple, pour passer l'objet 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 + ')');
)}
});
Vous pouvez transmettre les arguments de la fonction en tant qu'arguments à page.evaluate.
Exemple:
page.evaluate(function(arg1, arg2){
console.log(arg1); //Will print "hi"
console.log(arg2); //Will print "there"
}, "hi", "there");
Ne pouvez-vous pas simplement lier les arguments à la fonction?
page.evaluate.bind(args)(callbackFn)
Cela fonctionne pour moi:
page.evaluate("function() {document.body.innerHTML = '" + size + uid + "'}");
Signifie de tout mettre comme une chaîne. Quoi qu'il en soit, plus tard, cela devient une chaîne. Vérifiez la source de la bibliothèque.
Bien que vous puissiez passer des arguments dans evaluer (fonction, arg1, arg2, ...) , ceci est souvent un peu lourd. Particulièrement dans les cas où on passe plusieurs variables, ou pire, des fonctions.
Pour contourner cet obstacle, vous pouvez utiliser injectJs (nom du fichier) à la place.
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");
}
}
Où my_extra_functionality.js
est un fichier local dans le même répertoire:
var foo = 42;
var myFunction = function(){
return "Hello world!";
}