Puppeteer:在.evaluate()中传递变量

Cat*_*ton 85 javascript evaluate web-scraping puppeteer

我正在尝试将变量传递给Puppeteer中page.evaluate()函数,但是当我使用以下非常简化的示例时,变量是未定义的.evalVar

我是Puppeteer的新手,找不到任何构建的例子,所以我需要帮助将该变量传递给page.evaluate()函数,以便我可以在里面使用它.

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

  }

})();
Run Code Online (Sandbox Code Playgroud)

flo*_*zia 132

你必须将变量作为参数传递给pageFunction这样的:

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

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

}, evalVar);
Run Code Online (Sandbox Code Playgroud)

参数也可以序列化:https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pageevaluatepagefunction-args.

  • 另外,我实际上无法传递函数:var myFunction = function(){console.log("hello")}; 等待page.evaluate(func => func(),myFunction); 给我:`评估失败:TypeError:func不是函数`..为什么? (4认同)
  • 你好,你会如何传递多个变量? (3认同)
  • @chitzui:你不能将函数传递给`pate.evaluate()`。据说您可以使用“page.exposeFunction”来“暴露”它。有关更多信息,请参阅 /sf/answers/4062868491/。 (3认同)
  • 不要忘记在函数参数签名中键入“evalVar”,并将其作为传递给“evaluate”的参数(在代码示例的末尾)。 (2认同)

Meh*_*ash 42

我鼓励你坚持这种风格,因为它更方便可读.

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});
Run Code Online (Sandbox Code Playgroud)

  • 不同意,在这种情况下,数组的分配和销毁是一件大事,但是VM对其进行了优化。这种风格的优点是你不关心变量插入的顺序。这样您就可以根据需要检索变量(属性)。 (4认同)
  • 我不清楚这是否比直接传递变量更方便或更具可读性,如[此处](/sf/answers/3640886511/)所示。这只是分配和解构一个对象,增加垃圾收集活动并添加更多大括号。当主要问题是 OP 根本不传递参数时,这不是什么大问题,但也没有多大改进。 (3认同)
  • 我没有想到重新排序,但这似乎是一个毫无意义的特征——调用像 `fn(({baz, foo, quux}) => ..., {foo 这样的函数不太直观。 , quux, baz})`。如果我真的想更改顺序,我只需在两个地方执行此操作,以便代码读取一致。再说一遍,所有这些都很小,但这就是重点——答案让它看起来像是一个巨大的胜利,并没有真正解释你可以轻松地使用多个参数,或者最后一个参数是上下文参数的位置被传递到回调中,这是OP的根本问题。 (2认同)

Gra*_*ler 25

单变量:

你可以通过一个变量page.evaluate()使用的语法如下:

await page.evaluate(example => { /* ... */ }, example);
Run Code Online (Sandbox Code Playgroud)

注意:()除非要传递多个变量,否则不需要将变量括起来.

多个变量:

您可以通过多个变量page.evaluate()使用的语法如下:

await page.evaluate((example_1, example_2) => { /* ... */ }, example_1, example_2);
Run Code Online (Sandbox Code Playgroud)

注意:{}不必包含变量.


wol*_*olf 7

对于 pass a function,有两种方法可以做到。

// 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);
Run Code Online (Sandbox Code Playgroud)

您可以添加devtools: true到启动选项进行测试


har*_*rry 6

我花了很长时间才弄清楚console.log()in evaluate()无法在节点控制台中显示。

参考:https : //github.com/GoogleChrome/puppeteer/issues/1944

everything that is run inside the page.evaluate function is done in the context of the browser page. The script is running in the browser not in node.js so if you log it will show in the browsers console which if you are running headless you will not see. You also can't set a node breakpoint inside the function.

Hope this can help.