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) astext()
returns a list with two texts (Start
andEnd
), butcontains
will only check the first one//button[contains(text(), 'Middle')]
will return no results astext()
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
Javascript Odd and Even Separation in an Array of Numbers
Element Implicitly Has an 'Any' Type Because Index Expression Is Not of Type 'Number' [7015]
Using Setstate to Change Multiple Values Within an Array of Objects - Reactjs
Convert an Object With Multiple Values Per Key into Array of Objects in Js
How to Count Duplicate Value in an Array in JavaScript
Display a Loading Icon While Images Loads
Res.Sendfile in Node Express With Passing Data Along
How to Move the Mouse Pointer and Click With Selenium Webdriver JavaScript
Javascript (+) Sign Concatenates Instead of Giving Sum of Variables
How to Validate a Credit Card Number
How to Align Text Input Correctly in React Native
Reinitialize Slick Js After Successful Ajax Call
Change Image on Scroll Position
Javascript Onclick Increment Number
How to Set the Multi Sliders in One Page
Regex - Get All Characters After Last Slash in Url
Callback Function Cannot Access Variable Within Parent Function'S Scope