Puppeteer: Click on element with text

馋奶兔 提交于 2019-11-28 06:10:16

You may use a XPath selector with page.$x(expression):

const linkHandlers = await page.$x("//a[contains(text(), 'Some text')]");

if (linkHandlers.length > 0) {
  await linkHandlers[0].click();
} else {
  throw new Error("Link not found");
}

Check out clickByText in this gist for a complete example. It takes care of escaping quotes, which is a bit tricky with XPath expressions.

The current top answer by tokland only works on text nodes and not on nodes with other elements inside.

Short answer

This XPath expression will query a button which contains the text "Button text":

const [button] = await page.$x("//button[contains(., 'Button text')]");
if (button) {
    await button.click();
}

To also respect the <div class="elements"> surrounding the buttons, use the following code:

const [button] = await page.$x("//div[@class='elements']/button[contains(., 'Button text')]");

Explanation

To explain why using the text node (text()) is wrong in some cases, let's look at an example:

<div>
    <button>Start End</button>
    <button>Start <em>Middle</em> End</button>
</div>

First, let's check the results when using contains(text(), 'Text'):

  • //button[contains(text(), 'Start')] will return both two nodes (as expected)
  • //button[contains(text(), 'End')] will only return one nodes (the first) as text() returns a list with two texts (Start and End), but contains will only check the first one
  • //button[contains(text(), 'Middle')] will return no results as text() does not include the text of child nodes

Here are the XPath expressions for contains(., 'Text'), which works on the element itself including its child nodes:

  • //button[contains(., 'Start')] will return both two buttons
  • //button[contains(., 'End')] will again return both two buttons
  • //button[contains(., 'Middle')] will return one (the last button)

So in most cases, it makes more sense to use the . instead of text() in an XPath expression.

made quick solution to be able to use advanced css selectors like ":contains(text)"

so using this library you can just

const select = require ('puppeteer-select');

const element = await select(page).getElement('button:contains(Button text)');
await element.click()

You can also use page.evaluate() to click elements obtained from document.querySelectorAll() that have been filtered by text content:

await page.evaluate(() => {
  [...document.querySelectorAll('.elements button')].find(element => element.textContent === 'Button text').click();
});

Alternatively, you can use page.evaluate() to click an element based on its text content using document.evaluate() and a corresponding XPath expression:

await page.evaluate(() => {
  const xpath = '//*[@class="elements"]//button[contains(text(), "Button text")]';
  const result = document.evaluate(xpath, document, null, XPathResult.ANY_TYPE, null);

  result.iterateNext().click();
});

Here is my solution:

let selector = 'a';
    await page.$$eval(selector, anchors => {
        anchors.map(anchor => {
            if(anchor.textContent == 'target text') {
                anchor.click();
                return
            }
        })
    });

The solution is

(await page.$$eval(selector, a => a
            .filter(a => a.textContent === 'target text')
))[0].click()
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!