Puppeteer - 协议错误(Page.navigate):目标已关闭
Posted
技术标签:
【中文标题】Puppeteer - 协议错误(Page.navigate):目标已关闭【英文标题】:Puppeteer - Protocol error (Page.navigate): Target closed 【发布时间】:2019-01-08 18:44:38 【问题描述】:正如您在下面的示例代码中看到的那样,我正在使用 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 );
);
);
一些解释:
-
每次请求到达时,工作人员都会处理它并在最后杀死自己
每个工作人员使用单个页面创建一个新的浏览器实例,如果一个页面的加载时间超过 60 秒,它将重新尝试重新加载它(在同一页面中,因为可能已经加载了一些资源),超时时间为 120 秒
完成后,页面和浏览器都将关闭
我的问题是某些合法域出现了我无法解释的错误:
Error: Protocol error (Page.navigate): Target closed.
Error: Protocol error (Runtime.callFunctionOn): Session closed. Most likely the page has been closed.
我在一些 git 问题(我现在找不到)中读到,当页面重定向并在开头添加“www”时会发生这种情况,但我希望这是错误的...... 我有什么遗漏吗?
【问题讨论】:
有什么发现...? @Sajuuk 不幸的是不是真的......但我看了this 视频并认为失去集群并尝试PubSub架构,其中Puppeteer服务器将读取主机名,返回屏幕截图并移动到下一个一个 如果您最近升级到 macOS Catalina,请查看此问题:github.com/GoogleChrome/puppeteer/issues/5020 【参考方案1】:“目标关闭”是什么意思
当您通过puppeteer.launch
启动浏览器时,它将启动浏览器并连接到它。从那里您在打开的浏览器上执行的任何功能(如page.goto
)将通过Chrome DevTools Protocol 发送到浏览器。在此上下文中,目标表示选项卡。
Target closed 当你试图运行一个函数时抛出异常,但是目标(tab)已经关闭了。
类似的错误信息
最近更改了错误消息以提供更有意义的信息。它现在给出以下消息:
错误:协议错误(Target.activateTarget):会话关闭。该页面很可能已关闭。
为什么会发生
发生这种情况的原因有多种。
您使用了已关闭的资源
您看到此消息很可能是因为您关闭了选项卡/浏览器并且仍在尝试使用该资源。举个简单的例子:
const browser = await puppeteer.launch();
const page = await browser.newPage();
await browser.close();
await page.goto('http://www.google.com');
在这种情况下,浏览器已关闭,然后调用 page.goto
导致错误消息。大多数时候,它不会那么明显。也许一个错误处理程序已经在清理任务期间关闭了页面,而您的脚本仍在爬行。
浏览器崩溃或无法初始化
每隔几百个请求我也会遇到这种情况。 puppeteer 存储库中也有一个issue about this。当您使用大量内存或 CPU 能力时,情况似乎就是这样。也许你正在产生很多浏览器?在这些情况下,浏览器可能会崩溃或断开连接。
我没有找到解决这个问题的“灵丹妙药”。但是您可能想查看处理此类错误情况的库@987654323@(免责声明:我是作者),让您在发生错误时重试 URL。它还可以管理浏览器实例池,还可以简化您的代码。
【讨论】:
近 95% 的请求都得到了这个。 如果资源以某种方式从未打开过页面,会发生这种情况吗?比如初始化失败? 我会发布一个新的答案,但这是正确的,请记住在browser.close()
前面添加await
我得到了 100% 的某些网页请求
您也可以通过在其他命令中意外省略await
来获取此信息,例如page.keyboard.press('Enter')
【参考方案2】:
每次尝试运行我的 puppeteer 脚本时,我都遇到了同样的问题*。 above 没有为我解决这个问题。
我通过删除并重新安装 puppeteer 包使其工作:
npm remove puppeteer
npm i puppeteer
*我只在将 headless 选项设置为 'false` 时遇到了这个问题
【讨论】:
【参考方案3】:在 2021 年,我收到了非常相似的以下错误 Error: Error pdf creationError: Protocol error (Target.setDiscoverTargets): Target closed.
,我通过使用不同的 args 解决了它,所以如果您的生产服务器在 puppeteer.launch
obj 中有一个 pipe:true
标志,它将产生错误。
--disable-dev-shm-usage
标志也可以解决问题
以下解决方案适用于我:
const browser = await puppeteer.launch(
headless: true,
// pipe: true, <-- delete this property
args: [
'--no-sandbox',
'--disable-dev-shm-usage', // <-- add this one
],
);
【讨论】:
这些标志是什么意思?【参考方案4】:对我来说,从 args
中删除 '--single-process'
解决了这个问题。
puppeteerOptions:
headless: true,
args: [
'--disable-gpu',
'--disable-dev-shm-usage',
'--disable-setuid-sandbox',
'--no-first-run',
'--no-sandbox',
'--no-zygote',
'--deterministic-fetch',
'--disable-features=IsolateOrigins',
'--disable-site-isolation-trials',
// '--single-process',
],
【讨论】:
2021 年 6 月 30 日——这对我来说是正确的答案。 '--disable-site-isolation-trials' 为我工作【参考方案5】:我已经在这个线程上结束了几次,典型的罪魁祸首是我忘记了 await
一个 Puppeteer page
调用,该调用返回了一个承诺,导致了竞争条件。
这是一个最小的例子:
const puppeteer = require("puppeteer");
let browser;
(async () =>
browser = await puppeteer.launch();
const [page] = await browser.pages();
page.goto("https://www.***.com"); // whoops, forgot await!
)()
.catch(err => console.error(err))
.finally(async () => await browser.close())
;
输出是:
C:\Users\foo\Desktop\puppeteer-playground\node_modules\puppeteer\lib\cjs\puppeteer\common\Connection.js:217
this._callbacks.set(id, resolve, reject, error: new Error(), method );
^
Error: Protocol error (Page.navigate): Target closed.
at C:\Users\foo\Desktop\puppeteer-playground\node_modules\puppeteer\lib\cjs\puppeteer\common\Connection.js:217:63
在这种情况下,这似乎是一个不容错过的错误,但在较大的代码块中,并且 promise 是嵌套的或处于一个条件中,很容易被忽略。
忘记await
或page.click()
或其他承诺调用,例如Error: Protocol error (Runtime.callFunctionOn): Target closed.
,您会收到类似的错误,这可以在问题UnhandledPromiseRejectionWarning: Error: Protocol error (Runtime.callFunctionOn): Target closed. (Puppeteer) 中看到
这是对线程的贡献,作为错误的规范资源,可能不是 OP 问题的解决方案,尽管基本的竞争条件似乎是一个可能的原因。
【讨论】:
【参考方案6】:检查您的 jest-puppeteer.config.js 文件。 我犯了以下错误
module.exports =
launch:
headless: false,
browserContext: "default",
,
;
并在如下更正后
module.exports =
launch:
headless: false
,
browserContext: "default",
;
一切正常!!!
【讨论】:
以上是关于Puppeteer - 协议错误(Page.navigate):目标已关闭的主要内容,如果未能解决你的问题,请参考以下文章