0

Puppeteer: как работать с новой вкладкой и всплывающим окном

Как вы знаете, на многих сайтах при выполнении некоторых действий (например при нажатии на кнопку или переходе по ссылке) может открыться всплывающее окно или новая вкладка. Это может быть как надоедливая реклама, так и важная информация. Но в любом случае, в этот момент происходит фокусировка на новом окне или если её правильно не обработать, puppeteer не продолжит выполнение кода, а будет ожидать, пока вы не закроете всплывшее окно или не переключитесь на старую вкладку. Так давайте сделаем это!

Как открыть ссылку в новом окне вы можете прочитать в данной заметке.

Способ первый

Если мы знаем после какого действия (клика) должна открыться вкладка, то можно поступить следующим образом:

const puppeteer = require('puppeteer');         // подключаем puppeteer

const browser = await puppeteer.launch();       // запускаем браузер
const page = await browser.newPage();           // открываем новую вкладку
await page.goto('https://site.com');            // переходим на site.com       

await page.waitForSelector('#goto');            // ожидаем загрузку объекта
const link = await page.$('#goto');             // объявляем объект

const newPagePromise = new Promise(x => browser.once('targetcreated', target => x(target.page())));    // объявляем промис
await link.click();                             // кликаем, открывается новая вкладка
const newPage = await newPagePromise;           // объявляем новую вкладку/окно, теперь с ней можно работать
await newPage.close();                          // например, закрыть
...
await browser.close();                          // закрываем браузер

Как ограничить время ожидания новой вкладки вы можете прочитать в данной статье.

Способ второй

Если мы не знаем когда откроется новое окно или когда всплывающих окон много:

const puppeteer = require('puppeteer');         // подключаем puppeteer
const browser = await puppeteer.launch();       // запускаем браузер
 
browser.on('targetcreated', async (target) => { // данный блок перехватывает все новые события
  if (target.type() === 'page') {               // и если это новая страница/вкладка
         const page = await target.page();      // то объявляем ее
         const url = page.url();                // например, смотрим её url
         if (url.search('site.com') == -1){     // и если он не совпадает с нашим (всплывающая реклама на сторонний ресурс)
                  await page.close();           // закрываем такую вкладку
                  }
  }
});

await page.goto('https://site.com');            // переходим на site.com
...
await browser.close();                          // закрываем браузер

Тут стоим отметить, что при втором способе даже те новые страницы, которые вы открываете с помощью browser.newPage() попадут в этот обработчик. Т.е. если допустить ошибку в коде, puppeteer будет постоянно закрывать абсолютно все вкладки. Или производить с ними какие-то другие операции, которые делать не стоит.

Puppeteer popup событие

Начиная с puppeteer версии 1.12 для страницы было добавлено специальное событие ‘popup’, которое позволяет отлавливать новые вкладки и всплывающие окна. Используем его, переписав первый пример:

const puppeteer = require('puppeteer');         // подключаем puppeteer

const browser = await puppeteer.launch();       // запускаем браузер
const page = await browser.newPage();           // открываем новую вкладку
await page.goto('https://site.com');            // переходим на site.com       

await page.waitForSelector('#goto');            // ожидаем загрузку объекта
const link = await page.$('#goto');             // объявляем объект

const newPagePromise = new Promise(x => page.once('popup', x));

await link.click();                             // кликаем, открывается новая вкладка
const newPage = await newPagePromise;           // объявляем новую вкладку/окно, теперь с ней можно работать
await newPage.close();                          // например, закрыть
...
await browser.close();                          // закрываем браузер

Если, как во втором примере, необходимо отследить не единичное событие с всплывающим окном, а слушать все подобные действия, можно воспользоваться page.on(‘popup’, x).