puppeteer: ждать, что элемент виден?

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

const inputValidate = await page.$('input[value=validate]');
await inputValidate.click()

//I want to do something like that 
waitElemenentVisble('.btnNext ')

const btnNext = await page.$('.btnNext');
await btnNext.click();

Есть ли способ сделать это?

Ответ 1

Я думаю, вы можете использовать page.waitForSelector(selector[, options]) для этой цели.

const puppeteer = require('puppeteer');

puppeteer.launch().then(async browser => {
  const page = await browser.newPage();
  page
    .waitForSelector('#myId')
    .then(() => console.log('got it');
  browser.close();
});

Ответ 2

Вы можете использовать page.waitFor(), page.waitForSelector() или page.waitForXPath() для ожидания элемента на странице:

// Selectors

const css_selector   = '.btnNext';
const xpath_selector = '//*[contains(concat(" ", normalize-space(@class), " "), " btnNext ")]';

// Wait for CSS Selector

await page.waitFor( css_selector );
await page.waitForSelector( css_selector );

// Wait for XPath Selector

await page.waitFor( xpath_selector );
await page.waitForXPath( xpath_selector );

Примечание. В отношении фрейма вы также можете использовать frame.waitFor(), frame.waitForSelector() или frame.waitForXPath().

Ответ 3

Обновленный ответ с некоторыми оптимизациями:

const puppeteer = require('puppeteer');

(async() => {
    const browser = await puppeteer.launch({headless: true});
    const page = await browser.newPage();

    await page.goto('https://www.somedomain.com', {waitUntil: 'networkidle2'});
    await page.click('input[value=validate]');
    await page.waitForSelector('#myId');
    await page.click('.btnNext');
    console.log('got it');

    browser.close();
})();

Ответ 4

Обратите внимание, все вышеприведенные ответы неверны!

Потому что он отвечает за элемент, если он существует или находится, but NOT видим или не отображается

Правильный ответ - проверить размер элемента или видимость, используя page.waitFor() или page.waitForFunction(), см. Пояснение ниже.

// wait until present on the DOM
// await page.waitForSelector( css_selector );
// wait until "display"-ed
await page.waitForFunction("document.querySelector('.btnNext') && document.querySelector('.btnNext').clientHeight != 0");
// or wait until "visibility" not hidden
await page.waitForFunction("document.querySelector('.btnNext') && document.querySelector('.btnNext').style.visibility != 'hidden'");

const btnNext = await page.$('.btnNext');
await btnNext.click();

объяснение

Элемент, который существует в DOM страницы, не всегда видимый, если имеет свойство CSS display:none или visibility:hidden, поэтому использование page.waitForSelector(selector) не является хорошей идеей, давайте рассмотрим разницу во фрагменте ниже.

function isExist(selector) {
  let el = document.querySelector(selector);
  let exist = el.length != 0 ? 'Exist!' : 'Not Exist!';
  console.log(selector + ' is ' + exist)
}

function isVisible(selector) {
  let el = document.querySelector(selector).clientHeight;
  let visible = el != 0 ? 'Visible, ' + el : 'Not Visible, ' + el;
  console.log(selector + ' is ' + visible + 'px')
}

isExist('#idA');
isVisible('#idA');
console.log('=============================')
isExist('#idB')
isVisible('#idB')
.bd {border: solid 2px blue;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="bd">
  <div id="idA" style="display:none">#idA, hidden element</div>
</div>
<br>
<div class="bd">
  <div id="idB">#idB, visible element</div>
</div>