I’m trying to figure out how to click on elements that contain specific text using Puppeteer. The API doesn’t seem to have a straightforward method for this.
Here’s an example of what I’m working with:
<div class="container">
<button>Click me</button>
<a href="#">Go somewhere</a>
<div>Some content</div>
</div>
I want to be able to do something like:
await page.clickText('Click me', '.container');
Is there a built-in way to do this? Or do I need to write a custom function? Any tips or tricks would be really helpful. I’ve been scratching my head over this for a while now.
I’ve been in your shoes, Emma. Puppeteer doesn’t have a built-in method for clicking elements by text content, but I’ve found a workaround that’s served me well.
You can use page.evaluate() to run JavaScript in the context of the page. Here’s a custom function I’ve used:
const clickByText = async (page, text, parentSelector = 'body') => {
await page.evaluate((text, parent) => {
const elements = document.querySelector(parent).querySelectorAll('*');
for (const el of elements) {
if (el.textContent.trim() === text) {
el.click();
return;
}
}
}, text, parentSelector);
};
Then you can use it like this:
await clickByText(page, 'Click me', '.container');
This approach has been reliable for me across various projects. Hope it helps!
While the custom function approach is solid, I’ve found that leveraging Puppeteer’s built-in page.$x() method can be quite effective for text-based element selection. Here’s a technique I’ve used successfully:
async function clickElementByText(page, text) {
const elements = await page.$x(`//*[contains(text(), '${text}')]`);
if (elements.length > 0) {
await elements[0].click();
} else {
throw new Error(`Element with text '${text}' not found`);
}
}
This function uses XPath to locate elements containing the specified text, then clicks the first matching element. It’s concise and doesn’t require injecting JavaScript into the page context. You can call it like this:
await clickElementByText(page, 'Click me');
I’ve found this method to be both flexible and reliable across various page structures.
hey emma, i’ve had similar issues. one trick i use is combining page.$() with evaluate():
const clickText = async (page, text) => {
const el = await page.$(`*:not(script):not(style):contains('${text}')`);
if (el) await el.evaluate(e => e.click());
};
works great for me! give it a shot and lemme kno how it goes