Titereiro: passe a variável em .evaluate ()

128

Estou tentando passar uma variável para uma page.evaluate()função em Puppeteer , mas quando uso o seguinte exemplo muito simplificado, a variável evalVaré indefinida.

Eu sou novo no Puppeteer e não consigo encontrar nenhum exemplo para construir, então preciso de ajuda para passar essa variável para a page.evaluate()função para que possa usá-la internamente.

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

  }

})();
Cat Burston
fonte

Respostas:

188

Você deve passar a variável como um argumento da pageFunctionseguinte maneira:

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

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

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

Os argumentos também podem ser serializados: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pageevaluatepagefunction-args .

Flozia
fonte
3
Olá, como você passaria várias variáveis?
chitzui
4
Além disso, não consigo passar uma função: var myFunction = function () {console.log ("hello")}; aguardar page.evaluate (func => func (), myFunction); me dá: Evaluation failed: TypeError: func is not a function.. Por quê?
chitzui
1
Não se esqueça de digitar evalVartanto na assinatura do argumento da função quanto como um argumento passado para evaluate(no final do exemplo de código).
Flimm
2
@chitzui: Você não pode passar uma função para pate.evaluate(). Você pode supostamente 'expor' isso com page.exposeFunction. Para obter mais informações, consulte stackoverflow.com/a/58040978 .
knod
uma vez que tem os votos positivos mais altos, alguém já experimentou erros de linting com isso? especificamente com o parâmetro já declarado no escopo superior. além desse erro, isso funciona.
Mix Master Mike
61

Eu o encorajo a manter este estilo, porque é mais conveniente e legível .

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

Variável única:

Você pode passar uma variável para page.evaluate()usar a seguinte sintaxe:

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

Nota: Você não precisa incluir a variável (), a menos que vá passar várias variáveis.

Variáveis ​​múltiplas:

Você pode passar múltiplas variáveis para page.evaluate()usando a seguinte sintaxe:

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

Nota: Não {}é necessário incluir suas variáveis .

Grant Miller
fonte
12

Levei muito tempo para descobrir que console.log()na evaluate()não pode mostrar na consola nó.

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

tudo o que é executado dentro da função page.evaluate é feito no contexto da página do navegador. O script está sendo executado no navegador, não em node.js, portanto, se você registrar, ele será exibido no console do navegador, o que não será visto se estiver executando sem comando. Você também não pode definir um ponto de interrupção de nó dentro da função.

Espero que isso possa ajudar.

harrrrrrry
fonte
6

Para a aprovação a function, há duas maneiras de fazer isso.

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

Você pode adicionar devtools: trueopções de lançamento para teste

Lobo
fonte
E eu queria passar um objeto?
tramada
Como você adicionaria um argumento no segundo caso? por exemplo, eu quero adicionar uma string para seuFunc
user3568719
Você pode substituir yourFuncpor objeto se sua propriedade não for uma função. @tramada
wolf
func é semelhante a youFunc, então você pode chamar func (stringArg) assim como exec yourFunc @ user3568719
wolf
Você se importaria de mostrar como passaria um objeto para a janela e, em seguida, acessaria?
wuno
2

Eu tenho um exemplo datilografado que pode ajudar alguém novo na datilografia.

const hyperlinks: string [] = await page.evaluate((url: string, regex: RegExp, querySelect: string) => {
.........
}, url, regex, querySelect);
Srinivas Reddy Thatiparthy
fonte
Como você executa puppeteerem typescript? Você transpila para js cada vez que modifica seu código?
avalanche 1 de
Sim. Você pode dar uma olhada neste projeto aqui - github.com/srinivasreddy/companies-list
Srinivas Reddy Thatiparthy
-1

Com a 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);
//..

[veja também na página. $ eval para um único seletor]

voodoo417
fonte
Como isso responde à pergunta? Não vejo nenhuma variável que você está passando do contexto de teste para o contexto do navegador.
Ambroise Rabier