使用puppeteer单击可见元素

时间:2017-10-30 11:58:55

标签: javascript selenium puppeteer

我试图点击页面中的多个元素,但前提是它们是可见的。使用硒(使用is_displayed)非常容易,但我似乎无法在木偶操作中找到方法。 我试图使用像

这样的东西
try {
    await page
      .waitForSelector(id, visible=true, timeout=0)
      .then(() => {
        element.click()
      });
...

但是,如果它是一个简单的元素,则无效:

<a class="cookie-close" href="#">
OK
</a>

我也似乎无法在puppeteer中使用element.click方法找到方法。

6 个答案:

答案 0 :(得分:0)

与Selenium类似,正确的答案是使用Puppeteer的waitForSelector,它可以测试DOM元素的存在和可见性。

try {
  // Will throw err if element is not present and visible.
  await chromePage.waitForSelector("div.hello", {
    visible: true
  });
  await chromePage.click("div.hello");
} catch(err) {
  console.log(err);
}

答案 1 :(得分:0)

简短回答

const element = await page.waitForSelector('a.cookie-close', { visible: true });
await element.click();

这使用page.waitForSelector函数通过选择器a.cookie-close选择可见元素。查询选择器后,代码使用elementHandle.click单击它。

说明

只有函数page.waitForSelectorpage.waitForXPath内置有一个选项,用于检查元素是否不仅存在而且可见。如果使用样式属性visibility不是hidden,并且元素具有will check,则使用伪造者visible bounding box

确保元素不为空

即使该元素是可见的,它也可能为空(例如<span></span>)。如果还希望元素也不为空,则可以改用以下查询:

const element = await page.waitForSelector('SELECTOR:not(:empty)', { visible: true });

此外,这还将使用伪选择器:empty:not来确保元素包含子节点或文本。如果要查询元素内的特定文本,则可能要签出this answer

答案 2 :(得分:0)

这是一种更加惯用的方式,可在单击之前等待元素“显示”。结果应该与@joquarky解释的结果相同:

click() {
    let retries = 5;
    const hoverAndClick = () => {
        return this._element!.hover() // this._element is ElementHandle
            .then(() => {
                return this._element!.click();
            })
            .catch(err => {
                if (retries <= 0) {
                    throw err;
                }
                retries -= 1;
                sleep(1000).then(hoverAndClick);
            });
    };

    return hoverAndClick();
}

此处略有不同,是由于元素的任何父元素将其隐藏,因此我们在元素等待转换之前会重试几次。

答案 3 :(得分:-1)

您应该使用page.click()来实现点击。

请参阅Puppeteer的API文档中的page.click(selector,[options]):https://github.com/GoogleChrome/puppeteer/blob/HEAD/docs/api.md#pageclickselector-options

答案 4 :(得分:-1)

不确定它是否是最有效的方式,但你可以尝试这样的事情:

// returns null if element not present
let element = await page.evaluate(() => {
  return document.querySelector(id);
  });

// use jQuery to check if element is not hidden
if (element && !$(element).is(':hidden') {
  await page.click(id);
}

答案 5 :(得分:-1)

我遇到了同样的问题,并提出了这个解决方案:

await page.waitForSelector('#clickable');
await page.evaluate(() => {
  let el = document.querySelector('#clickable');
  if (isVisible(el)) {
    el.click();
    return true;
  }
  return false;

  function isVisible(el) {
    if (el.offsetParent === null && el !== document.body) {
      return false; // not connected to document
    }
    if (el.offsetWidth <= 0 || el.offsetHeight <= 0) {
      return false; // no width or height
    }
    let style = el.style;
    if (style.display === "none" || style.visibility === "hidden" || style.opacity === "0") {
      return false; // has a 'hidey' css attribute
    }
    if (el === document.body) {
      return true;
    }
    return isVisible(el.offsetParent);
  }
});

这会检查元素是否实际附加到文档,它至少有一些宽度和高度,并且CSS样式display:none隐藏了元素及其任何祖先,visibility:hidden ,或opacity:0

请注意,如果元素被非常规手段隐藏,例如巨大的负边距/填充,这可能无效。