Почему кукловод сообщает: «UnhandledPromiseRejectionWarning: Ошибка: навигация не удалась, потому что браузер отключился!»? - PullRequest
0 голосов
/ 05 февраля 2019

У меня есть простой скрипт node.js для захвата скриншотов нескольких веб-страниц.Похоже, что меня споткнуло где-то вдоль линии с использованием async / await, но я не могу понять, где.В настоящее время я использую кукольника v1.11.0.

const puppeteer = require('puppeteer');

//a list of sites to screenshot
const papers =
{
     nytimes: "https://www.nytimes.com/",
     wapo: "https://www.washingtonpost.com/"
};

//launch puppeteer, do everything in .then() handler
puppeteer.launch({devtools:false}).then(function(browser){

//create a load_page function that returns a promise which resolves when screenshot is taken
async function load_page(paper){

    const url = papers[paper];

    return new Promise(async function(resolve, reject){

        const page = await browser.newPage();
        await page.setViewport({width:1024, height: 768});

        //screenshot on first console message
        page.once("console", async console_msg => {        
            await page.pdf({path: paper + '.pdf',
                            printBackground:true,
                            width:'1024px',
                            height:'768px',
                            margin: {top:"0px", right:"0px", bottom:"0px", left:"0px"}
                        });

            //close page
            await page.close();

            //resolve promise
            resolve();
        });

        //go to page
        await page.goto(url, {"waitUntil":["load", "networkidle0"]});

    })     
}

//step through the list of papers, calling the above load_page()
async function stepThru(){
    for(var p in papers){
        if(papers.hasOwnProperty(p)){
            //wait to load page and screenshot before loading next page
            await load_page(p);
        }
    }

    //close browser after loop has finished (and all promises resolved)
    await browser.close();  
}

//kick it off
stepThru();

//getting this error message:
//UnhandledPromiseRejectionWarning: Error: Navigation failed because browser has disconnected!

});

1 Ответ

0 голосов
/ 05 февраля 2019

Ошибка Navigation failed because browser has disconnected обычно означает, что сценарии узла, запустившие Puppeteer, заканчиваются, не дожидаясь завершения действий Puppeteer.Следовательно, это проблема с некоторыми ожиданиями, как вы сказали.

О вашем скрипте я внес некоторые изменения, чтобы он работал:


1 - во-первых, вы не ожидаете(асинхронный) конец функции stepThru, поэтому измените

stepThru();

на

await stepThru();

и

puppeteer.launch({devtools:false}).then(function(browser){

на

puppeteer.launch({devtools:false}).then(async function(browser){

(Я добавил async)


2 - я изменил способ управления обещаниями goto и pagce.once

Обещание в формате PDF теперь

new Promise(async function(resolve, reject){
    //screenshot on first console message
    page.once("console", async () => {
      await page.pdf({path: paper + '.pdf', printBackground:true, width:'1024px', height:'768px', margin: {top:"0px", right:"0px", bottom:"0px", left:"0px"} });
      resolve();
    });
})

и он несет единоличную ответственность, только создание PDF.


3 - тогда я управлял обещаниями page.goto и PDF с Promise.all

await Promise.all([
    page.goto(url, {"waitUntil":["load", "networkidle2"]}),
    new Promise(async function(resolve, reject){
        // ... pdf creation as above        
    })
]);


4 - я переместил page.close после Promise.all

await Promise.all([
    // page.goto
    // PDF creation
]);

await page.close();
resolve();


И теперь все работает, вот полный рабочий скрипт

const puppeteer = require('puppeteer');

//a list of sites to screenshot
const papers =
{
  nytimes: "https://www.nytimes.com/",
  wapo: "https://www.washingtonpost.com/"
};
//launch puppeteer, do everything in .then() handler
puppeteer.launch({devtools:false}).then(async function(browser){

  //create a load_page function that returns a promise which resolves when screenshot is taken
  async function load_page(paper){
    const url = papers[paper];
    return new Promise(async function(resolve, reject){
      const page = await browser.newPage();
      await page.setViewport({width:1024, height: 768});

      await Promise.all([
        page.goto(url, {"waitUntil":["load", "networkidle2"]}),
        new Promise(async function(resolve, reject){

          //screenshot on first console message
          page.once("console", async () => {
            await page.pdf({path: paper + '.pdf', printBackground:true, width:'1024px', height:'768px', margin: {top:"0px", right:"0px", bottom:"0px", left:"0px"} });
            resolve();
          });
        })
      ]);

      await page.close();
      resolve();
    })
  }

  //step through the list of papers, calling the above load_page()
  async function stepThru(){
    for(var p in papers){
      if(papers.hasOwnProperty(p)){
        //wait to load page and screenshot before loading next page
        await load_page(p);
      }
    }

    await browser.close();
  }

  await stepThru();
});

Пожалуйстаобратите внимание, что: - я изменил networkidle0 на networkidle2, потому что веб-сайту nytimes.com требуется очень много времени, чтобы получить состояние 0 сетевых запросов (из-за AD и т. д.).Вы можете ждать networkidle0, очевидно, но это зависит от вас, это выходит за рамки вашего вопроса (в этом случае увеличьте время ожидания page.goto) - сайт www.washingtonpost.com переходит на ошибку TOO_MANY_REDIRECTS, поэтому я изменился на washingtonpost.com но я думаю, что вам стоит больше об этом поговорить.Для тестирования скрипта я использовал больше раз сайт nytimes и другие сайты.Опять же: это выходит за рамки вашего вопроса

Дайте мне знать, если вам нужна дополнительная помощь ?

...