Marionnettiste: passer la variable dans .evaluate ()

128

J'essaie de passer une variable dans une page.evaluate()fonction dans Puppeteer , mais lorsque j'utilise l'exemple très simplifié suivant, la variable evalVarn'est pas définie.

Je suis nouveau sur Puppeteer et je ne trouve aucun exemple sur lequel s'appuyer, j'ai donc besoin d'aide pour transmettre cette variable dans la page.evaluate()fonction afin de pouvoir l'utiliser à l'intérieur.

const puppeteer = require('puppeteer');

(async() => {

  const browser = await puppeteer.launch({headless: false});
  const page = await browser.newPage();

  const evalVar = 'WHUT??';

  try {

    await page.goto('https://www.google.com.au');
    await page.waitForSelector('#fbar');
    const links = await page.evaluate((evalVar) => {

      console.log('evalVar:', evalVar); // appears undefined

      const urls = [];
      hrefs = document.querySelectorAll('#fbar #fsl a');
      hrefs.forEach(function(el) {
        urls.push(el.href);
      });
      return urls;
    })
    console.log('links:', links);

  } catch (err) {

    console.log('ERR:', err.message);

  } finally {

    // browser.close();

  }

})();
Chat Burston
la source

Réponses:

188

Vous devez passer la variable comme argument à pageFunctionceci:

const links = await page.evaluate((evalVar) => {

  console.log(evalVar); // 2. should be defined now
  

}, evalVar); // 1. pass variable as an argument

Les arguments peuvent également être sérialisés: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pageevaluatepagefunction-args .

flozia
la source
3
Bonjour, comment passeriez-vous plusieurs variables?
chitzui
4
De plus, je ne suis pas vraiment capable de passer une fonction: var myFunction = function () {console.log ("hello")}; attendre page.evaluate (func => func (), maFonction); me donne: Evaluation failed: TypeError: func is not a function.. Pourquoi?
chitzui
1
N'oubliez pas de saisir à la evalVarfois la signature de l'argument de la fonction et en tant qu'argument passé à evaluate(à la fin de l'exemple de code).
Flimm
2
@chitzui: Vous ne pouvez pas passer une fonction à pate.evaluate(). Vous pouvez supposément «l'exposer» avec page.exposeFunction. Pour plus d'informations, consultez stackoverflow.com/a/58040978 .
knod le
puisque cela a les votes positifs les plus élevés, est-ce que quelqu'un a connu des erreurs de peluchage avec cela? spécifiquement avec le paramètre déjà déclaré dans la portée supérieure. à part cette erreur, cela fonctionne.
Mix Master Mike
61

Je vous encourage à vous en tenir à ce style, car il est plus pratique et plus lisible .

let name = 'jack';
let age  = 33;
let location = 'Berlin/Germany';

await page.evaluate(({name, age, location}) => {

    console.log(name);
    console.log(age);
    console.log(location);

},{name, age, location});
Mehdi Raash
la source
40

Variable unique:

Vous pouvez passer une variable à l' page.evaluate()aide de la syntaxe suivante:

await page.evaluate(example => { /* ... */ }, example);

Remarque: vous n'avez pas besoin de placer la variable dans (), sauf si vous allez passer plusieurs variables.

Variables multiples:

Vous pouvez transmettre plusieurs variables à l' page.evaluate()aide de la syntaxe suivante:

await page.evaluate((example_1, example_2) => { /* ... */ }, example_1, example_2);

Remarque: il {}n'est pas nécessaire d' inclure vos variables à l'intérieur .

Grant Miller
la source
12

Il m'a fallu un certain temps pour comprendre que console.log()dans evaluate()ne peut pas s'afficher dans la console du nœud.

Réf: https://github.com/GoogleChrome/puppeteer/issues/1944

tout ce qui est exécuté dans la fonction page.evaluate se fait dans le contexte de la page du navigateur. Le script s'exécute dans le navigateur et non dans node.js, donc si vous vous connectez, il affichera dans la console du navigateur que si vous utilisez headless, vous ne verrez pas. Vous ne pouvez pas non plus définir un point d'arrêt de nœud dans la fonction.

J'espère que cela peut vous aider.

harrrrrrry
la source
6

Pour passer a function, il y a deux façons de le faire.

// 1. Defined in evaluationContext
await page.evaluate(() => {
  window.yourFunc = function() {...};
});
const links = await page.evaluate(() => {
  const func = window.yourFunc;
  func();
});


// 2. Transform function to serializable(string). (Function can not be serialized)
const yourFunc = function() {...};
const obj = {
  func: yourFunc.toString()
};
const otherObj = {
  foo: 'bar'
};
const links = await page.evaluate((obj, aObj) => {
   const funStr = obj.func;
   const func = new Function(`return ${funStr}.apply(null, arguments)`)
   func();

   const foo = aObj.foo; // bar, for object
   window.foo = foo;
   debugger;
}, obj, otherObj);

Vous pouvez ajouter devtools: trueaux options de lancement pour le test

Loup
la source
Et je voulais passer un objet?
tramada
Comment ajouteriez-vous un argument dans le 2ème cas? par exemple, je veux ajouter passer une chaîne à yourFunc
user3568719
Vous pouvez remplacer yourFuncpar un objet si votre propriété n'est pas une fonction. @tramada
wolf
func est similaire à youFunc , donc vous pouvez appeler func (stringArg) tout comme exec yourFunc @ user3568719
wolf
Cela vous dérangerait-il de montrer comment passer un objet à une fenêtre et y accéder?
wuno
2

J'ai un exemple dactylographié qui pourrait aider quelqu'un de nouveau en tapuscrit.

const hyperlinks: string [] = await page.evaluate((url: string, regex: RegExp, querySelect: string) => {
.........
}, url, regex, querySelect);
Srinivas Reddy Thatiparthy
la source
Comment exécutez-vous puppeteeren tapuscrit? Transpilez-vous en js chaque fois que vous modifiez votre code?
avalanche1
Oui. Vous pouvez consulter ce projet ici - github.com/srinivasreddy/companies-list
Srinivas Reddy Thatiparthy
-1

Avec page. $$ eval

//..
const page = await browser.newPage();
const hrefs = await page.$$eval('#fbar #fsl a', as => as.map(a => a.href));
console.log(hrefs);
//..

[voir aussi à la page. $ eval pour un seul sélecteur]

vaudou417
la source
Comment cela répond-il à la question? Je ne vois aucune variable que vous transmettez du contexte de test au contexte du navigateur.
Ambroise Rabier le