Как ускорить кукловода? - PullRequest
4 голосов
/ 11 июля 2020

На веб-странице есть кнопка, и кукольник должен нажать эту кнопку, как только кнопка станет видимой. Эта кнопка не всегда видна и становится видимой для всех одновременно. Поэтому мне нужно постоянно обновлять sh, чтобы увидеть, что кнопка стала видимой. Для этого я написал этот сценарий ниже:

    const browser = await puppeteer.launch({
        headless: true,
        args: ['--no-sandbox']
    });
    const page = await browser.newPage()
    await page.setViewport({ width: 1920, height: 1080})


//I am calling my pageRefresher method here

async function pageRefresher(page,browser, url) {
        try {
            await page.goto(url, {waitUntil: 'networkidle2'})
            try {
                await page.waitForSelector('#ourButton', {timeout: 10});
                await page.click('#ourButton')
                console.log(`clicked!`)
                await browser.close()
            } catch (error) {
                console.log('catch2 ' + counter + ' '  + error)
                counter += 1
                await pageRefresher(page, browser, url)
            }
        }catch (error) {
            console.log('catch3' + error)
            await browser.close();
        }
}

Как видите, мой метод рекурсивен. Он переходит на эту страницу и ищет эту кнопку. Если кнопки нет, он снова вызывает себя для повторения того же задания, пока не найдет и не щелкнет эту кнопку.

На самом деле сейчас он работает хорошо. Но это медленно. Я запускаю этот скрипт, пока я открываю ту же страницу на своем рабочем столе chrome и начинаю обновлять sh эту страницу вручную. И я всегда побеждаю, я всегда нажимаю эту кнопку перед кукловодом.

Как я могу ускорить этот процесс? Сценарий не должен проигрывать человеку, у которого есть только ручное управление, например, кнопка F5.

Ответы [ 2 ]

3 голосов
/ 12 июля 2020

Сценарий не должен проиграть человеку, у которого есть только ручное управление, такое как кнопка F5.

Это происходит потому, что иногда правила, которым следует кукловод, намного строже, чем то, что мы считаем «полностью загруженная веб-страница». Даже если вы, как человек, можете решить, находится ли желаемый элемент уже в DOM (потому что вы видите, что элемент есть) или его нет (потому что вы его не видите). Например: вы увидите, что вашей кнопки нет, даже если фоновое изображение все еще загружается в фоновом режиме, или веб-шрифты все еще не загружены, а у вас есть резервные шрифты, но кукловод ждет определенных c событий в фоновом режиме, чтобы получить разрешение либо на go блоку catch (тайм-аут), либо на захват желаемого элемента (waitForSelector успешно). Это действительно может зависеть от сайта, который вы посещаете, но вы можете ускорить процесс распознавания желаемого элемента.

Я даю несколько примеров и идеи, как этого добиться.

Способы ускорения распознавания желаемого элемента

1.) Если вам не нужны все сетевые подключения для вашей задачи, вы можете ускорить загрузку страницы, заменив waitUntil: 'networkidle2' на waitUntil: 'domcontentloaded' как это событие обычно происходит раньше и запускается, когда #ourButton уже присутствует в DOM.

Возможные варианты page.goto / page.reload:

  • load - считайте, что навигация завершена при срабатывании события load.
  • domcontentloaded - считайте, что навигация завершена, когда запускается событие DOMContentLoaded.
  • networkidle0 - учтите завершение навигации при наличии не более 0 сетевых подключений в течение не менее 500 мс.
  • networkidle2 - считайте, что навигация завершена, когда имеется не более 2 сетевых подключений для не менее 500 ms.

Вы выигрываете, потому что networkidle2 слишком строгий. Вам может понадобиться эта опция (например, вы посещаете одностраничное приложение или позже вам потребуются данные из стороннего сетевого подключения, например файлы cookie), но если это не обязательно, вы получите лучшую производительность с domcontentloaded.

2.) Вместо постоянного перехода к одному и тому же URL-адресу вы можете использовать метод page.reload в al oop, например:

await page.goto(url, { waitUntil: 'domcontentloaded' })
let selectorExists = await page.$('#ourButton')

while (selectorExists === null) {
  await page.reload({ waitUntil: 'domcontentloaded' })
  console.log('reload')
  selectorExists = await page.$('#ourButton')
}
await page.click('#ourButton')
// code goes on...

Его главное преимущество в том, что вы могут сократить и упростить вашу функцию pageRefresher. Но я также испытал лучшую производительность (хотя я не проводил тестов, но я чувствовал, что это намного быстрее, чем повторное открытие страницы).

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

await page.setRequestInterception(true)
page.on('request', (request) => {
  if (request.resourceType() === 'image') request.abort()
  else request.continue()
})

[источник]

Список resourceType - с.

1 голос
/ 13 июля 2020

Попробуйте просто не ждать goto:

page.goto(url) // no await because it doesn't have to resolve fully
await page.waitForSelector('#ourButton') // await this because we need it to be there

Некоторым людям нравится Promise.race для этого, но этот способ проще

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