Click on Element Containing Text in Puppeteer

How to click on element with text in Puppeteer

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.

Click on element containing text in puppeteer

With help, I have solved it like this.

const [linkHandler] = await page.$x("//div[contains(., 'textcontained')]");
if(linkHandler)
{
await linkHandler.click();
}

Puppeteer: how to find element by text

You caan use XPath with page.$x() and then call elementHandle.focus():

const [element] = await page.$x('//span[contains(text(), "Name")]');
await element.focus();

Puppeteer - click on span with specified text

You can try and use page.evaluate and than use querySelectorAll and filter the li by text than use a forEach to click on the il with the specific text.

await page.evaluate(() => {
Array.from(document.querySelectorAll('li')).filter(li => {
return li.innerText == 'First Option' // filter il for specific text
}).forEach(element => {
if (element) element.click(); // click on il with specific text
});
});

If the first one does not work you can try.

await page.evaluate(() => {
Array.from(document.querySelectorAll('div > div > ul > li')).filter(li => {
return li.innerText == 'First Option' // filter il for specific text
}).forEach(element => {
if (element) element.click(); // click on il with specific text
});
});

You could also give this a try and i think this would be the best way todo it.

await page.evaluate(() => {
const elements = [...document.querySelectorAll('div > div > ul > li')];
const targetElement = elements.find(e => e.innerText == 'First Option');
if (targetElement) targetElement.click();
});

or

await page.evaluate(() => {
const elements = [...document.querySelectorAll('li')];
const targetElement = elements.find(e => e.innerText == 'First Option');
if (targetElement) targetElement.click();
});

How to click a button by name or text with puppeteer?

From your browser, open the page where the button sits.
Right click on the page and select "Inspect".

Then, from the DOM code, right click on the button, and select "Copy > Copy JS path".

That selector can be easily used in puppeteer.

How to find an element by text and click on it using puppeteer js

Something like this:

const puppeteer = require('puppeteer');

(async function main() {
try {
const browser = await puppeteer.launch({ headless: false, defaultViewport: null });
const [page] = await browser.pages();

await page.goto('https://example.org/');

const [element] = await page.$x('//a[text()="More information..."]');
// For partial match:
// const [element] = await page.$x('//a[contains(text(), "More")]');
await element.click();
} catch (err) {
console.error(err);
}
})();

How to click on a link that has a certain content in puppeteer?

First, we have to find element by text.

/**
* findElemByText - Find an Element By Text
*
* @param {String} str case-insensitive string to search
* @param {String} selector = '*' selector to search
* @param {String} leaf = 'outerHTML' leaf of the element
* @return {Array} array of elements
*/
function findElemByText({str, selector = '*', leaf = 'outerHTML'}){
// generate regex from string
const regex = new RegExp(str, 'gmi');

// search the element for specific word
const matchOuterHTML = e => (regex.test(e[leaf]))

// array of elements
const elementArray = [...document.querySelectorAll(selector)];

// return filtered element list
return elementArray.filter(matchOuterHTML)
}

// usage
// findElemByText({str: 'Example', leaf: 'innerHTML', selector: 'title'});
// findElemByText({str: 'Example', selector: 'h1'});
// findElemByText({str: 'Example'});

Save it in same folder as your puppeteer script, name it script.js.

Now, we can use this in our puppeteer script. We can use ElementHandle, but for simplicity of understanding, I'll use .evaluate() function provided with puppeteer.

const puppeteer = require('puppeteer');

(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');

// expose the function
await page.addScriptTag({path: 'script.js'});

// Find Element by Text and Click it
await page.evaluate(() => {
// click the first element
return findElemByText({str: 'More'})[0].click();
});

// Wait for navigation, Take Screenshot, Do other stuff
await page.screenshot({path: 'screenshot.png'});
await browser.close();
})();

Do not copy paste the code above, try to understand it and type them yourself. If the code above fails, try to find why it's failing.



Related Topics



Leave a reply



Submit