我有一个非常简单的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();
})()
答案 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();
})()
addScriptTag
和readFileSync
您可以将该功能保存到单独的文件,并使用addScriptTag
。
await page.addScriptTag({path: 'my-script.js'});
或evaluate
与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;
};
与承诺完美无瑕地合作,
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()
不是这项工作的正确工具。
page.exposeFunction(name,puppeteerFunction)
puppeteerFunction回调函数,在Puppeteer的上下文中称为 。
&#39;在木偶的背景下&#39;有点模糊,但请查看evaluate()
的文档:
page.evaluateHandle(pageFunction,... args)
pageFunction要在页面上下文中进行评估的函数
exposeFunction()
没有公开要在页面内运行的函数,但是会在页面中公开要在节点中运行的函数。
我必须使用evaluate()
:
答案 2 :(得分:1)
您的问题可能与以下事实有关:page.exposeFunction()
将使您的函数返回Promise
(要求使用async
和await
)。发生这种情况是因为您的函数不是running inside your browser,而是在您的nodejs
应用程序内部,并且其结果在浏览器代码之间来回发送。这就是为什么传递给page.exposeFunction()
的函数现在返回promise而不是实际结果的原因。并且它说明了为什么未定义window
函数的原因,因为您的函数运行在nodejs
(而不是浏览器)内部,并且在nodejs
内部没有window
定义。< / p>
相关问题: