Кукольник - Ошибка протокола (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 });
            });
    });
}

Некоторое объяснение:

  1. Каждый раз, когда приходит запрос, работник обрабатывает его и в конце убивает себя
  2. Каждый работник создает новый экземпляр браузера с одной страницей, и, если загрузка страницы заняла более 60 секунд, он попытается перезагрузить его (на той же странице, поскольку, возможно, некоторые ресурсы уже были загружены) с тайм-аутом 120 секунд.
  3. После завершения и страница, и браузер будут закрыты

Моя проблема в том, что некоторые легитимные домены получают ошибки, которые я не могу объяснить:

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",
  ],
},
Другие вопросы по тегам