为什么我不能在使用Puppeteer的exposeFunction()函数中访问'window'?

时间:2018-01-16 12:19:18

标签: node.js google-chrome headless-browser puppeteer

我有一个非常简单的Puppeteer脚本,它使用exposeFunction()在无头Chrome中运行。

(async function(){

    var log = console.log.bind(console),
        puppeteer = require('puppeteer');


    const browser = await puppeteer.launch();
    const page = await browser.newPage();

    var functionToInject = function(){
        return window.navigator.appName;
    }

    await page.exposeFunction('functionToInject', functionToInject);

    var data = await page.evaluate(async function(){
        console.log('woo I run inside a browser')
        return await functionToInject();
    });

    console.log(data);

    await browser.close();

})()

这失败了:

ReferenceError: window is not defined

这是指注入的功能。如何在无头Chrome中访问window

我知道我可以改为evaluate(),但这不适用于我动态传递的函数:

(async function(){

    var log = console.log.bind(console),
        puppeteer = require('puppeteer');

    const browser = await puppeteer.launch();
    const page = await browser.newPage();

    var data = await page.evaluate(async function(){
        console.log('woo I run inside a browser')
        return window.navigator.appName;
    });

    console.log(data);

    await browser.close();

})()

3 个答案:

答案 0 :(得分:4)

evaluate函数

您可以使用evaluate传递动态脚本

(async function(){
    var puppeteer = require('puppeteer');
    const browser = await puppeteer.launch();
    const page = await browser.newPage();

    var functionToInject = function(){
        return window.navigator.appName;
    }

    var data = await page.evaluate(functionToInject); // <-- Just pass the function
    console.log(data); // outputs: Netscape

    await browser.close();
})()

addScriptTagreadFileSync

您可以将该功能保存到单独的文件,并使用addScriptTag

使用该功能
await page.addScriptTag({path: 'my-script.js'});

evaluatereadFileSync

await page.evaluate(fs.readFileSync(filePath, 'utf8'));

或者将参数化的函数作为字符串传递给page.evaluate

await page.evaluate(new Function('foo', 'console.log(foo);'), {foo: 'bar'});

动态制作新功能

你还需要其他更多方法来解决这个问题吗?如何将其变成runnable函数:D?

function runnable(fn) {
  return new Function("arguments", `return ${fn.toString()}(arguments)`);
}

以上将使用提供的参数创建一个新函数。我们可以传递任何我们想要的功能。

例如以下window函数以及参数

function functionToInject() {
  return window.location.href;
};

与承诺完美无瑕地合作,

function functionToInject() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(window.location.href);
    }, 5000);
  });
}

并带参数,

async function functionToInject(someargs) {
  return someargs; // {bar: 'foo'}
};

使用evaluate

调用所需的功能
var data = await page.evaluate(runnable(functionToInject), {bar: "foo"});
console.log(data); // shows the location

答案 1 :(得分:2)

exposeFunction()不是这项工作的正确工具。

来自Puppeteer docs

  

page.exposeFunction(name,puppeteerFunction)

     

puppeteerFunction回调函数,在Puppeteer的上下文中称为

&#39;在木偶的背景下&#39;有点模糊,但请查看evaluate()的文档:

  

page.evaluateHandle(pageFunction,... args)

     

pageFunction要在页面上下文中进行评估的函数

exposeFunction()没有公开要在页面内运行的函数,但是会在页面中公开要在节点中运行的函数

我必须使用evaluate()

答案 2 :(得分:1)

您的问题可能与以下事实有关:page.exposeFunction()将使您的函数返回Promise(要求使用asyncawait)。发生这种情况是因为您的函数不是running inside your browser,而是在您的nodejs应用程序内部,并且其结果在浏览器代码之间来回发送。这就是为什么传递给page.exposeFunction()的函数现在返回promise而不是实际结果的原因。并且它说明了为什么未定义window函数的原因,因为您的函数运行在nodejs(而不是浏览器)内部,并且在nodejs内部没有window定义。< / p>

相关问题:

  1. exposeFunction() does not work after goto()
  2. exposed function queryseldtcor not working in 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. How to pass a function in Puppeteers .evaluate() method?
  10. How can I dynamically inject functions to evaluate using Puppeteer?