Как ждать страницы в кукольнике

#javascript #node.js #parsing #puppeteer

Вопрос:

У меня есть большой массив адресов, которые мне нужно открыть одновременно и получить данные. из-за ограничений сервера я не могу открыть более 10 вкладок одновременно. Как дождаться появления новой бесплатной страницы в сериалеnumbers.forEach? Я понимаю, что могу проверить, есть ли browser.pages () Но как заставить цикл подождать на одной итерации свободной вкладки и не переходить на следующую итерацию?

 const puppeteer = require('puppeteer');
let numberOfOpenPages;

let serialNumbers = ['FVFDT2GCQ6L7', 'DLXFG3X2DFJ1', 'FVFDT2GCQ6L7', 'DLXFG3X2DFJ1', 'FVFDT2GCQ6L7', 'DLXFG3X2DFJ1'];

async function processArray() {
    const browser = await puppeteer.launch({ headless: true });


    serialNumbers.forEach(async (item, i) => {
                
// new page and then get data 
                const page = await browser.newPage();
                await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36');

                await page.goto(`https://support.apple.com/en_US/specs/${item}`);

                await page.waitForSelector('.article_link');

                await page.click('.article_link');
                await page.waitForSelector('#article');

                const specs = await page.evaluate(() => {
                    let article = document.querySelector('h1').innerHTML;
                    return `${article}`;
                });

                console.log(specs);
                await page.close();
        
// close browser when all pages is closed 
        numberOfOpenPages = (await browser.pages()).length;
        console.log(numberOfOpenPages);

        if (numberOfOpenPages <= 1) {
            await browser.close();
        }
    })
}

processArray()

 

Комментарии:

1. Я сделал это с помощью setTimeout, но иногда он запускает больше вкладок одновременно, чем нужно. Но ошибка невелика. Если есть более правильные решения, я буду рад узнать

2. разве вы не подумывали об использовании puppeteer-cluster ? он используется для очень схожих целей

Ответ №1:

Может быть, что-то вроде этого?

 const browser = await puppeteer.launch({ headless: true });

const serialNumbers = ['FVFDT2GCQ6L7', 'DLXFG3X2DFJ1', 'FVFDT2GCQ6L7', 'DLXFG3X2DFJ1', 'FVFDT2GCQ6L7', 'DLXFG3X2DFJ1'];
const pageLimit = 10;

for (let i = 0; i < pageLimit; i  ) {
  processPage(await browser.newPage());
}

async function processPage(page) {
    if (serialNumbers.length === 0) {
        await page.close();
        if ((await browser.pages()).length <= 1) await browser.close();
        return;
    }

    const serialNumber = serialNumbers.shift();
    await page.goto(`https://support.apple.com/en_US/specs/${serialNumber}`);

    // Process the page...

    processPage(page);
}
 

Ответ №2:

Я сделал это с помощью setTimeout, но иногда он запускает больше вкладок одновременно, чем нужно. Но ошибка невелика.

Если есть более правильные решения, я буду рад узнать

 // const { copyFileSync } = require('fs');
const puppeteer = require('puppeteer');
let numberOfOpenPages;
let i = 0;

let serialNumbers = ['FVFDT2GCQ6L7', 'DLXFG3X2DFJ1', 'FVFDT2GCQ6L7', 'DLXFG3X2DFJ1', 'FVFDT2GCQ6L7', 'DLXFG3X2DFJ1', 'FVFDT2GCQ6L7', 'DLXFG3X2DFJ1', 'FVFDT2GCQ6L7'];

async function newPage(serial, browser) {

    numberOfOpenPages = (await browser.pages()).length;
    console.log(numberOfOpenPages);
    if (numberOfOpenPages < 10) {
        // new page and then get data 
        const page = await browser.newPage();
        await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36');

        await page.goto(`https://support.apple.com/en_US/specs/${serialNumbers[serial]}`);

        await page.waitForSelector('.article_link');

        await page.click('.article_link');
        await page.waitForSelector('#article');

        const specs = await page.evaluate(() => {
            let article = document.querySelector('h1').innerHTML;
            return `${article}`;
        });

        console.log(specs);
        await page.close();

        // close browser when all pages is closed 
        numberOfOpenPages = (await browser.pages()).length;
        // console.log(numberOfOpenPages);

        // if (numberOfOpenPages <= 1) {
        //     await browser.close();
        //     console.log('браузер закрыт!')
        // }
    } else {
        setTimeout(() => {
            newPage(serial, browser);
        }, 3000); // не ставить меньше 1 сек чтобы не совпадало сразу в один свободный слот 
    }
}

async function processArray() {
    const browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'], headless: true });
                     //  set your counter to 1

function myLoop () {           //  create a loop function
   setTimeout(function () {    //  call a 3s setTimeout when the loop is called
      console.log('запускаем', i); 
      newPage(i, browser);         //  your code here
      i  ;                   //  increment the counter
      if (i < serialNumbers.length) { //if the counter < 10, call the loop function
         myLoop();             //  ..  again which will trigger another 
      } else console.log('end loop');                       //  ..  setTimeout()
   }, 500)
}

myLoop();   
 
}

processArray()