Titiritero: pasar variable en .evaluate ()

128

Estoy tratando de pasar una variable a una page.evaluate()función en Puppeteer , pero cuando uso el siguiente ejemplo muy simplificado, la variable evalVarno está definida.

Soy nuevo en Puppeteer y no puedo encontrar ningún ejemplo para construir, así que necesito ayuda para pasar esa variable a la page.evaluate()función para poder usarla dentro.

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();

  }

})();
Gato burston
fuente

Respuestas:

188

Tienes que pasar la variable como un argumento pageFunctionasí:

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

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

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

Los argumentos también se pueden serializar: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pageevaluatepagefunction-args .

Flozia
fuente
3
Hola, ¿cómo pasarías varias variables?
Chitzui
4
Además, no puedo pasar una función: var myFunction = function () {console.log ("hola")}; aguardar página.evaluar (func => func (), myFunction); me da: Evaluation failed: TypeError: func is not a function.. ¿Por qué?
chitzui
1
No olvide escribir evalVartanto la firma del argumento de la función como un argumento pasado a evaluate(al final del ejemplo de código).
Flimm
2
@chitzui: No puedes pasar una función a pate.evaluate(). Supuestamente puedes 'exponerlo' con page.exposeFunction. Para obtener más información, consulte stackoverflow.com/a/58040978 .
Knod
dado que tiene los votos a favor más altos, ¿alguien ha experimentado errores con esto? específicamente con el parámetro ya declarado en el ámbito superior. Aparte de este error, esto funciona.
Mix Master Mike
61

Te animo a que sigas este estilo, porque es más conveniente y legible. .

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
fuente
40

Variable única:

Puede pasar una variable para page.evaluate()usar la siguiente sintaxis:

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

Nota: No es necesario que incluya la variable (), a menos que vaya a pasar varias variables.

Varias variables:

Se pueden pasar múltiples variables a page.evaluate()utilizar la siguiente sintaxis:

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

Nota:{} No es necesario incluir sus variables .

Grant Miller
fuente
12

Me tomó bastante tiempo para darse cuenta de que console.log()en evaluate()no se puede mostrar en la consola de nodo.

Ref: https://github.com/GoogleChrome/puppeteer/issues/1944

todo lo que se ejecuta dentro de la función page.evaluate se realiza en el contexto de la página del navegador. El script se está ejecutando en el navegador, no en node.js, por lo que si inicia sesión, se mostrará en la consola del navegador, que si está ejecutando sin cabeza, no verá. Tampoco puede establecer un punto de interrupción de nodo dentro de la función.

Espero que esto pueda ayudar.

harrrrrrry
fuente
6

Para el pase a function, hay dos formas de hacerlo.

// 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);

Puede agregar devtools: truea las opciones de lanzamiento para la prueba

lobo
fuente
¿Y quería pasar un objeto?
Tramada
¿Cómo agregaría un argumento en el segundo caso? por ejemplo, quiero agregar pasar una cadena a yourFunc
user3568719
Puede reemplazar yourFunccon objeto si su propiedad no es una función. @tramada
lobo
func es similar a youFunc, por lo que puede llamar a func (stringArg) como el ejecutivo yourFunc @ user3568719
wolf
¿Le importaría mostrar cómo pasaría un objeto a la ventana y luego accedería?
wuno
2

Tengo un ejemplo de mecanografiado que podría ayudar a alguien nuevo en mecanografiado.

const hyperlinks: string [] = await page.evaluate((url: string, regex: RegExp, querySelect: string) => {
.........
}, url, regex, querySelect);
Srinivas Reddy Thatiparthy
fuente
¿Cómo se ejecuta puppeteeren mecanografiado? ¿Transpila a js cada vez que modifica su código?
avalancha1
Si. Puede echar un vistazo a este proyecto aquí: github.com/srinivasreddy/companies-list
Srinivas Reddy Thatiparthy
-1

Con página. $$ eval

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

[ver también en page. $ eval para un solo selector]

vudú417
fuente
¿Cómo responde eso a la pregunta? No veo ninguna variable que esté pasando del contexto de prueba al contexto del navegador.
Ambroise Rabier