Кукольник - Ошибка протокола (Page.navigate): Цель закрыта
Как видно из приведенного ниже примера кода, я использую 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" в начале, но я надеюсь, что это неверно... Есть что-то, что я пропускаю?
8 ответов
Я не могу сказать вам, почему происходит эта ошибка, но я также испытываю это каждые несколько сотен запросов. Существует проблема по этому поводу в хранилище кукловода.
Возможно, вы захотите проверить библиотеку puppeteer-cluster, которая обрабатывает подобные ошибки и позволяет вам повторить URL. Он может управлять пулом экземпляров браузера и даже упростит ваш код. (Отказ от ответственности: я автор)
Для меня удаление
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',
],
}
Я заходил в эту ветку несколько раз, и типичный виновник - то, что я забыл Кукольнику
page
вызов, который вернул обещание, вызвав состояние гонки.
Вот минимальный пример того, как это может выглядеть:
const puppeteer = require("puppeteer");
let browser;
(async () => {
browser = await puppeteer.launch();
const [page] = await browser.pages();
page.goto("https://www.stackoverflow.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
В этом случае это похоже на ошибку, которую нельзя пропустить, но в большем фрагменте кода, а обещание вложено или находится в состоянии, это легко не заметить.
Вы получите аналогичную ошибку, если забудете
await
а
page.click()
или другой вызов обещания, например,
Error: Protocol error (Runtime.callFunctionOn): Target closed.
, который можно увидеть в вопросе UnhandledPromiseRejectionWarning: Ошибка: Ошибка протокола (Runtime.callFunctionOn): Цель закрыта. (Кукольник)
Это вклад в поток как канонический ресурс для ошибки и не может быть решением проблемы OP, хотя фундаментальное состояние гонки кажется вероятной причиной.
У меня была одна и та же проблема каждый раз, когда я пытался запустить свой сценарий кукольника *. Выше не решить эту проблему для меня.
Я заставил его работать, удалив и переустановив пакет кукловода:
npm remove puppeteer
npm i puppeteer
* Я столкнулся с этой проблемой только при установке параметра headless на 'false'
В 2021 году я получаю очень похожую следующую ошибку
Error: Error pdf creationError: Protocol error (Target.setDiscoverTargets): Target closed.
, Я решил это, поиграв с разными аргументами, поэтому, если на вашем производственном сервере
pipe:true
флаг в
puppeteer.launch
obj это приведет к ошибкам.
Также
--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
],
});
После нескольких часов разочарований я понял, что это происходит, когда он переходит на новую страницу, и мне нужно использовать
Проверьте свой файл jest-puppeteer.config.js. Я сделал ошибку ниже
module.exports = {
launch: {
headless: false,
browserContext: "default",
},
};
и после исправления, как показано ниже
module.exports = {
launch: {
headless: false
},
browserContext: "default",
};
все работало отлично!!!
Решение ниже работает для меня:
puppeteer: {
headless: true,
args: [
"--no-sandbox",
"--disable-setuid-sandbox",
"--disable-dev-shm-usage",
"--disable-accelerated-2d-canvas",
"--no-first-run",
"--no-zygote",
// "--single-process",
"--disable-gpu",
],
},