Очередь асинхронных задач - PullRequest
       5

Очередь асинхронных задач

0 голосов
/ 09 сентября 2018

Я пытаюсь создать скрипт, который берет список URL-адресов, переходит на сайт и делает снимок экрана.

Мне удалось заставить это работать с кукловодом. Однако проблема, с которой я столкнулся, заключается в том, что, когда я скажу 50 URL-адресов в списке, он попытается запустить кукольные сеансы для всех из них одновременно, что означает, что большинство времени истекает до загрузки сайта, и он может сделать снимок экрана.

Я обнаружил, что могу успешно запустить 10 сразу, поэтому я хочу настроить систему очередей для этого.

parser.on('readable', function(){
  while(record = parser.read()){
      counter +=1;
      console.log(record.URL);


      (async (url = record.URL, name = record.shortURL, counter1 = counter) => {
      const browser = await puppeteer.launch( {defaultViewport: {width: 1024, height:768} } );
      const page = await browser.newPage();
      await page.goto(url);
      title = await page.title();
      domainRegex = /^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n?]+)/img;
      match = domainRegex.exec(url);

      width = 1024;//await page.viewport().width;
      height = 1000;//await page.viewport.height();
      await page.screenshot({path: "Screenshots/"+counter1+". "+match[1] + "- " +title.replace(/[\W_]+/g,"")+".jpg", clip : {x:0, y:0, width: width, height: height}});

      await browser.close();    
      })();

  }
});

Ответы [ 4 ]

0 голосов
/ 10 сентября 2018

Возможно, вы захотите взглянуть на кукловод-кластер (отказ от ответственности: я автор).

Вы можете сделать это так:

(async () => {
    // create a cluster that handles 10 parallel browsers
    const cluster = await Cluster.launch({
        concurrency: Cluster.CONCURRENCY_BROWSER,
        maxConcurrency: 10,
    });

    // define the task
    await cluster.task(async ({ page, data: { counter, record} }) => {
        const url = record.URL;

        await page.goto(url);
        title = await page.title();
        domainRegex = /^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n?]+)/img;
        match = domainRegex.exec(url);

        width = 1024;//await page.viewport().width;
        height = 1000;//await page.viewport.height();
        await page.screenshot({path: "Screenshots/"+counter+". "+match[1] + "- " +title.replace(/[\W_]+/g,"")+".jpg", clip : {x:0, y:0, width: width, height: height}});
    });

    // queue your jobs
    parser.on('readable', function () {
        while (record = parser.read()) {
            counter += 1;
            cluster.queue({ counter, record });
        }
    });
})();

Это будет обрабатывать 10 параллельных экземпляров браузера, а также будет заботиться о сбоях браузера и обработке ошибок.

0 голосов
/ 09 сентября 2018

Если вы хотите запустить набор обещаний в последовательности, вы можете использовать Promise.mapSeries из пакета Bluebird. Я понимаю, что это будет означать добавление дополнительного пакета, но это просто и не требует от вас создания системы очередей.

http://bluebirdjs.com/docs/api/promise.mapseries.html

0 голосов
/ 10 сентября 2018

Приведенный ниже код первоначально запустит 10 сеансов. После завершения каждого сеанса он удаляет следующую запись и запускает другую, пока не останется больше записей. Это обеспечит одновременную работу макс. 10.

parser.on('readable', async () => {
    const maxNumberOfSessions = 10;
    let counter = 0;

    await Promise.all(Array.from({length: maxNumberOfSessions}, dequeueRecord));
    console.log("All records have been processed.");

    function dequeueRecord() {
        const nextRecord = parser.read();
        if(nextRecord) return processRecord(nextRecord).then(dequeueRecord);
    }

    async function processRecord(record) {
        const number = ++counter;
        console.log("Processing record #" + number + ": " + record.URL);

        const browser = await puppeteer.launch({defaultViewport: {width: 1024, height: 768}});
        const page = await browser.newPage();
        await page.goto(record.URL);
        const title = await page.title();
        const domainRegex = /^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n?]+)/img;
        const match = domainRegex.exec(record.URL);

        const width = 1024; // await page.viewport().width;
        const height = 1000; // await page.viewport().height;
        await page.screenshot({path: "Screenshots/" + number + ". " + match[1] + "- " + title.replace(/[\W_]+/g, "") + ".jpg", clip: {x: 0, y: 0, width, height}});

        await browser.close();    
    }
});
0 голосов
/ 09 сентября 2018

Если вы хотите запустить все из них поочередно, вы можете превратить это в асинхронную функцию и ожидать ее. Таким образом, он будет работать один за другим.

// let's separate it for readability
async function getRecord(record, counter) {
    const url = record.URL,
        name = record.shortURL,
        counter1 = counter;
    const browser = await puppeteer.launch({
        defaultViewport: {
            width: 1024,
            height: 768
        }
    });
    const page = await browser.newPage();
    await page.goto(url);
    title = await page.title();
    domainRegex = /^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n?]+)/img;
    match = domainRegex.exec(url);

    width = 1024; //await page.viewport().width;
    height = 1000; //await page.viewport.height();
    await page.screenshot({
        path: "Screenshots/" + counter1 + ". " + match[1] + "- " + title.replace(/[\W_]+/g, "") + ".jpg",
        clip: {
            x: 0,
            y: 0,
            width: width,
            height: height
        }
    });

    await browser.close();
}

parser.on('readable', async function() { // <-- here we make it async
    while (record = parser.read()) {
        counter += 1;
        console.log(record.URL);
        await getRecord(record, counter) // <-- and we await each call
    }
});

Существуют и другие способы, такие как Promise.map и for..of, но давайте пока оставим это проще.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...