简体   繁体   English

如何将变量传递给评估函数?

[英]How can I pass variable into an evaluate function?

I'm trying to pass a variable into a page.evaluate() function in Puppeteer , but when I use the following very simplified example, the variable evalVar is undefined.我正在尝试将变量传递给Puppeteer中的page.evaluate()函数,但是当我使用以下非常简化的示例时,变量evalVar未定义。

I'm new to Puppeteer and can't find any examples to build on, so I need help passing that variable into the page.evaluate() function so I can use it inside.我是 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();

  }

})();

You have to pass the variable as an argument to the pageFunction like this:您必须将变量作为参数传递给pageFunction ,如下所示:

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

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

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

You can pass in multiple variables by passing more arguments to page.evaluate() :您可以通过向page.evaluate()传递更多参数来传递多个变量:

await page.evaluate((a, b c) => { console.log(a, b, c) }, a, b, c)

The arguments must either be serializable as JSON or JSHandle s of in-browser objects: https://pptr.dev/#?show=api-pageevaluatepagefunction-args参数必须可序列化为 JSON 或浏览器内对象的JSHandlehttps ://pptr.dev/#?show=api-pageevaluatepagefunction-args

I encourage you to stick on this style, because it's more convenient and readable .我鼓励你坚持这种风格,因为它更方便可读

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

Single Variable:单变量:

You can pass one variable to page.evaluate() using the following syntax:您可以使用以下语法将一个变量传递给page.evaluate()

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

Note: You do not need to enclose the variable in () , unless you are going to be passing multiple variables.注意:您不需要将变量括在()中,除非您要传递多个变量。

Multiple Variables:多变量:

You can pass multiple variables to page.evaluate() using the following syntax:您可以使用以下语法将多个变量传递给page.evaluate()

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

Note: Enclosing your variables within {} is not necessary.注意:不需要将变量包含在{}中。

It took me quite a while to figure out that console.log() in evaluate() can't show in node console.我花了很长时间才发现evaluate()中的console.log()无法在节点控制台中显示。

Ref: https://github.com/GoogleChrome/puppeteer/issues/1944参考: 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.在 page.evaluate 函数中运行的所有内容都是在浏览器页面的上下文中完成的。 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.该脚本在浏览器中运行,而不是在 node.js 中,因此如果您登录,它将显示在浏览器控制台中,如果您以无头方式运行,您将看不到。 You also can't set a node breakpoint inside the function.您也不能在函数内设置节点断点。

Hope this can help.希望这能有所帮助。

For pass a function , there are two ways you can do it.对于传递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);

You can add devtools: true to the launch options for test您可以将devtools: true添加到启动选项以进行测试

I have a typescript example that could help someone new in typescript.我有一个打字稿示例,可以帮助打字稿新手。

const hyperlinks: string [] = await page.evaluate((url: string, regex: RegExp, querySelect: string) => {
.........
}, url, regex, querySelect);

Slightly different version from @wolf answer above.与上面的@wolf 答案略有不同的版本。 Make code much more reusable between different context.使代码在不同上下文之间更加可重用。

// util functions
export const pipe = (...fns) => initialVal => fns.reduce((acc, fn) => fn(acc), initialVal)
export const pluck = key => obj => obj[key] || null
export const map = fn => item => fn(item)
// these variables will be cast to string, look below at fn.toString()
const updatedAt = await page.evaluate(
  ([selector, util]) => {
    let { pipe, map, pluck } = util
    pipe = new Function(`return ${pipe}`)()
    map = new Function(`return ${map}`)()
    pluck = new Function(`return ${pluck}`)()

    return pipe(
      s => document.querySelector(s),
      pluck('textContent'),
      map(text => text.trim()),
      map(date => Date.parse(date)),
      map(timeStamp => Promise.resolve(timeStamp))
    )(selector)
  },
  [
    '#table-announcements tbody td:nth-child(2) .d-none',
    { pipe: pipe.toString(), map: map.toString(), pluck: pluck.toString() },
  ]
)

Also not that functions inside pipe cant used something like this也不是管道内的函数不能使用这样的东西

// incorrect, which is i don't know why
pipe(document.querySelector) 

// should be 
pipe(s => document.querySelector(s))

I'm trying to pass a variable into a page.evaluate() function in Puppeteer , but when I use the following very simplified example, the variable evalVar is undefined.我试图将变量传递到Puppeteer中page.evaluate()函数中,但是当我使用以下非常简单的示例时,变量evalVar是未定义的。

I'm new to Puppeteer and can't find any examples to build on, so I need help passing that variable into the page.evaluate() function so I can use it inside.我是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();

  }

})();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM