Chrome 如何在Puppeteers.evaluate()方法中传递函数

w6lpcovy  于 2022-12-06  发布在  Go
关注(0)|答案(5)|浏览(460)

每当我试图传递一个函数时,就像这样:

var myFunc = function() { console.log("lol"); };

await page.evaluate(func => {
 func();
 return true;
}, myFunc);

我得到:

(node:13108) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Evaluation failed: TypeError: func is not a function
at func (<anonymous>:9:9)
(node:13108) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

为什么?怎么做才正确?
谢谢你,谢谢你
让我澄清一下:我这样做是因为我想先找到一些DOM元素,然后在函数中使用它们,更像这样(简化):

var myFunc = function(element) { element.innerHTML = "baz" };

await page.evaluate(func => {
  var foo = document.querySelector('.bar');
  func(foo);
  return true;
}, myFunc);
qpgpyjmq

qpgpyjmq1#

You cannot pass a function directly into page.evaluate() , but you can call another special method ( page.exposeFunction ), which expose your function as a global function (also available in as an attribute of your page window object), so you can call it when you are inside page.evaluate() :

var myFunc = function() { console.log("lol"); };
await page.exposeFunction("myFunc", myFunc);

await page.evaluate(async () => {
   await myFunc();
   return true;
});

Just remember that page.exposeFunction() will make your function return a Promise , then, you need to use async and await . This happens because your function will not be running inside your browser, but inside your nodejs application.

  1. exposeFunction() does not work after goto()
  2. Why can't I access 'window' in an exposeFunction() function with Puppeteer?
  3. How to use evaluateOnNewDocument and exposeFunction?
  4. exposeFunction remains in memory?
  5. Puppeteer: pass variable in .evaluate()
  6. Puppeteer evaluate function
  7. allow to pass a parameterized funciton as a string to page.evaluate
  8. Functions bound with page.exposeFunction() produce unhandled promise rejections
  9. exposed function queryseldtcor not working in puppeteer
  10. How can I dynamically inject functions to evaluate using Puppeteer?
yizd12fk

yizd12fk2#

类似的问题已经在 puppet 戏issue中讨论过。
有几种方法可以处理你的问题。第一条规则是保持简单。

计算函数

这是最快的方法,您只需传递函数并执行它。

await page.evaluate(() => {
  var myFunc = function(element) { element.innerHTML = "baz" };
  var foo = document.querySelector('.bar');
  myFunc(foo);
  return true;
});

预先公开函数

您可以使用page.evaluate或page.addScriptTag预先公开该函数

// add it manually and expose to window
await page.evaluate(() => {
  window.myFunc = function(element) { element.innerHTML = "baz" };
});

// add some scripts
await page.addScriptTag({path: "myFunc.js"});

// Now I can evaluate as many times as I want
await page.evaluate(() => {
  var foo = document.querySelector('.bar');
  myFunc(foo);
  return true;
});

使用元素句柄

页.$(选择器)

您可以将项目控制代码传递给。evaluate,并视情况进行变更。

const bodyHandle = await page.$('body');
const html = await page.evaluate(body => body.innerHTML, bodyHandle);

页.$eval

您可以将一个元素作为目标,然后根据需要进行更改。

const html = await page.$eval('.awesomeSelector', e => {
e.outerHTML = "whatever"
});

诀窍是read the docs并保持简单。

kx7yvsdv

kx7yvsdv3#

使用参数传递函数

//手动添加并向窗口公开

await page.evaluate(() => {
      window.myFunc = function(element) { element.innerHTML = "baz" };
    });

//然后调用上面声明的函数

await page.evaluate((param) => {
         myFunc (param);
    }, param);
66bbxpm5

66bbxpm54#

//  External function to run inside evaluate context
function getData() {
        return document.querySelector('title').textContent;
    }

function mainFunction(url, extractFunction){
    let browser = await puppeteer.launch({});
    let page = await browser.newPage();

    await page.goto(url);

    let externalFunction = Object.assign(extractFunction);

    let res = await this.page.evaluate(externalFunction)

    console.log(res);
}
    

// call it here
mainFunction('www.google.com',getData);
cotxawn7

cotxawn75#

我喜欢evaluateOnNewDocument,因为我想确保我的脚本代码在其他任何事情之前运行。
例如,如果要查找总阻塞时间Web重要信息:

const perfObserver = () => {
    // Important that you don't run for this URL.
    if (window.location.href === 'about:blank') return;

    window.totalBlockingTime = 0;

    console.log(window.location.href);
    console.log('TBT', totalBlockingTime);

    const observer = new PerformanceObserver(function (list) {
      let perfEntries = list.getEntries();
      for (const perfEntry of perfEntries) {
        let longtask = perfEntry.duration - 50
        if (longtask) console.log(perfEntry);
        totalBlockingTime += longtask;
      }
      console.log({ totalBlockingTime });
    });
    observer.observe({ type: "longtask", buffered: true });
  };

  const browser = await puppeteer.launch({
    headless: true,
    devtools: false
  });

  const page = await browser.newPage();

  await page.evaluateOnNewDocument(perfObserver);

  await page.goto("https://stackoverflow.com/");

  const performance = await page.evaluate(() => window.totalBlockingTime);
  
  console.log(performance);

  await browser.close();

您也可以从父作用域向函数传递参数。请参阅上面的文档链接。

相关问题