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

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

我有一个非常简单的 Puppeteer使用 exposeFunction() 的脚本在 headless 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

指的是注入(inject)函数。如何在 headless 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();

})()

最佳答案

评估函数

您可以使用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'});

或使用readFileSync评估

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

也可以完美地使用 promises,

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

关于node.js - 为什么我不能使用 Puppeteer 在 exposeFunction() 函数中访问 'window'?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48281130/

相关文章:

javascript - 在 Google 计算引擎 Docker 镜像上安装 Node.js 时出错

javascript - 如何从 Node 脚本放入 REPL

Node.js、multer 和 req.body 为空

jquery - npm install jquery 错误/saveError ENOENT/无效依赖

google-chrome - 如何在 Chrome 中禁用 Flash?

javascript - 监听 Web Worker 的创建?

javascript - jQuery touchmove 未在 Chrome 模拟器中注册

javascript - NodeJS 服务器无法处理多个用户

javascript - 带有自己的 headless 浏览器的 Heisenbug

javascript - PhantomJS 返回空主体