web-dev-qa-db-fra.com

Passer des arguments avec page.evaluate

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?

53
TheFist

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);
}
69
Weston

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

65
Bala Anirudh

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
3
Tomas Randus

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 + ')');       
    )}
});
2
Aakil Fernandes

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");
2
YTL

Ne pouvez-vous pas simplement lier les arguments à la fonction?

page.evaluate.bind(args)(callbackFn)
0
user2977636

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. 

0
Tomas Randus

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");
    }
}

my_extra_functionality.js est un fichier local dans le même répertoire:

var foo = 42;
var myFunction = function(){
    return "Hello world!";
}
0
ChickenFeet