正如您在下面的示例代码中看到的那样,我正在使用Puppeteer与Node中的一组工作人员按给定的URL运行多个网站截图请求:
const cluster = require('cluster');
const express = require('express');
const bodyParser = require('body-parser');
const puppeteer = require('puppeteer');
async function getScreenshot(domain) {
let screenshot;
const browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'] });
const page = await browser.newPage();
try {
await page.goto('http://' + domain + '/', { timeout: 60000, waitUntil: 'networkidle2' });
} catch (error) {
try {
await page.goto('http://' + domain + '/', { timeout: 120000, waitUntil: 'networkidle2' });
screenshot = await page.screenshot({ type: 'png', encoding: 'base64' });
} catch (error) {
console.error('Connecting to: ' + domain + ' failed due to: ' + error);
}
await page.close();
await browser.close();
return screenshot;
}
if (cluster.isMaster) {
const numOfWorkers = require('os').cpus().length;
for (let worker = 0; worker < numOfWorkers; worker++) {
cluster.fork();
}
cluster.on('exit', function (worker, code, signal) {
console.debug('Worker ' + worker.process.pid + ' died with code: ' + code + ', and signal: ' + signal);
Cluster.fork();
});
cluster.on('message', function (handler, msg) {
console.debug('Worker: ' + handler.process.pid + ' has finished working on ' + msg.domain + '. Exiting...');
if (Cluster.workers[handler.id]) {
Cluster.workers[handler.id].kill('SIGTERM');
}
});
} else {
const app = express();
app.use(bodyParser.json());
app.listen(80, function() {
console.debug('Worker ' + process.pid + ' is listening to incoming messages');
});
app.post('/screenshot', (req, res) => {
const domain = req.body.domain;
getScreenshot(domain)
.then((screenshot) =>
try {
process.send({ domain: domain });
} catch (error) {
console.error('Error while exiting worker ' + process.pid + ' due to: ' + error);
}
res.status(200).json({ screenshot: screenshot });
})
.catch((error) => {
try {
process.send({ domain: domain });
} catch (error) {
console.error('Error while exiting worker ' + process.pid + ' due to: ' + error);
}
res.status(500).json({ error: error });
});
});
}
一些解释:
我的问题是,一些合法的域名出现了我无法解释的错误:
Error: Protocol error (Page.navigate): Target closed.
Error: Protocol error (Runtime.callFunctionOn): Session closed. Most likely the page has been closed.
我读了一些git问题(我现在找不到),当页面重定向并在开始时添加'www'时会发生这种情况,但我希望它是假的...有什么我缺少的吗?
当您通过puppeteer.launch
启动浏览器时,它将启动浏览器并连接到它。从那里你在打开的浏览器上执行的任何功能(如page.goto
)将通过Chrome DevTools Protocol发送到浏览器。目标在此上下文中表示选项卡。
当您尝试运行函数时,会抛出Target关闭异常,但目标(选项卡)已经关闭。
最近更改了错误消息以提供更有意义的信息。它现在给出以下消息:
错误:协议错误(Target.activateTarget):会话已关闭。页面很可能已关闭。
这可能发生的原因有多种。
const browser = await puppeteer.launch();
const page = await browser.newPage();
await browser.close();
await page.goto('http://www.google.com');
在这种情况下,浏览器被关闭,之后,调用page.goto
导致错误消息。大多数时候,它不会那么明显。也许错误处理程序在清理任务期间已经关闭了页面,而您的脚本仍在爬行。