What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Use Pyppeteer’s XPath lookup, Page.xpath() (or its Page.Jx() shorthand), and restrict the expression to button. For an exact label, use normalize-space(.), count the returned elements, and click only when the count is the one you expect.
A reliable selector is //button[normalize-space(.)="Submit"]. Pyppeteer returns a list of matching element handles, so checking that list before clicking prevents an accidental click on the wrong control when a page contains duplicate or partial labels.
The direct method: XPath plus a match-count check
Pyppeteer’s project documentation maps Puppeteer’s $x() method to Page.xpath(), with Page.Jx() as a shorthand. The method returns a list, even when only one element matches. That makes the safe pattern explicit:
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →buttons = await page.xpath('//button[normalize-space(.)="Submit"]')
if len(buttons) != 1:
raise RuntimeError(f'Expected one Submit button, got {len(buttons)}')
await buttons[0].click()
normalize-space(.) trims leading and trailing whitespace and collapses runs of whitespace before comparing the button’s string value. The dot represents the button element, so text in descendant spans is included.
#1 Best Overall
- CRISP CLARITY: This 23.8″ Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
- INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
- THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors
- WORK SEAMLESSLY: This sleek monitor is virtually bezel-free on three sides, so the screen looks even bigger for the viewer. This minimalistic design also allows for seamless multi-monitor setups that enhance your workflow and boost productivity
- A BETTER READING EXPERIENCE: For busy office workers, EasyRead mode provides a more paper-like experience for when viewing lengthy documents
Exact text, partial text, and nested text
Exact normalized text
Use an equality test when the label is known and should be unique:
buttons = await page.xpath('//button[normalize-space(.)="Save changes"]')
This will match a button whose rendered DOM text is equivalent to Save changes even if the HTML contains line breaks or extra spaces around the words. It will not match a different label such as Save changes and close.
Partial text
Use contains() only when a partial label is intentional:
buttons = await page.xpath('//button[contains(normalize-space(.), "Save")]')
Partial matching is broader. It can return Save, Save changes, and Save as draft at the same time. Inspect or count the candidates before choosing one; never assume that the first result is the desired control.
Text inside child elements
The expression normalize-space(.) evaluates the button’s complete string value, including text in descendants such as <span> or an icon label. This is usually more dependable than text(), which can overlook text split into child nodes. If the wording is supplied only through an attribute such as aria-label or title, it is not button text and requires an attribute predicate instead.
Rank #2
- CRISP CLARITY: This 22 inch class (21.5″ viewable) Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
- 100HZ FAST REFRESH RATE: 100Hz brings your favorite movies and video games to life. Stream, binge, and play effortlessly
- SMOOTH ACTION WITH ADAPTIVE-SYNC: Adaptive-Sync technology ensures fluid action sequences and rapid response time. Every frame will be rendered smoothly with crystal clarity and without stutter
- INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
- THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors
A complete runnable Pyppeteer example
The following script opens a page, waits for the initial network to settle, selects an exact button label, verifies uniqueness, clicks it, and closes Chromium even if an error occurs.
import asyncio
from pyppeteer import launch
URL = 'https://example.com'
LABEL = 'Submit'
async def main():
browser = await launch(headless=True)
try:
page = await browser.newPage()
await page.goto(URL, {'waitUntil': 'networkidle2', 'timeout': 60000})
xpath = '//button[normalize-space(.)="Submit"]'
buttons = await page.xpath(xpath)
if len(buttons) != 1:
raise RuntimeError(
f'Expected exactly one {LABEL!r} button, got {len(buttons)}'
)
await buttons[0].click()
print('Clicked the Submit button')
finally:
await browser.close()
if __name__ == '__main__':
asyncio.get_event_loop().run_until_complete(main())
Replace URL and LABEL with values for your page. The XPath literal must contain the same label that appears in the DOM, not necessarily the text you see in a screenshot. A successful run prints the confirmation after the click; a zero- or multi-match result raises an error instead of making an arbitrary choice.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteWait for a button that appears after load
Many interfaces insert controls only after JavaScript finishes rendering. Querying immediately after navigation can therefore return an empty list. Wait for the same XPath before retrieving the handles:
xpath = '//button[normalize-space(.)="Continue"]'
await page.waitForXPath(xpath, {'timeout': 15000})
buttons = await page.xpath(xpath)
if len(buttons) != 1:
raise RuntimeError(f'Expected one Continue button, got {len(buttons)}')
await buttons[0].click()
A timeout means the expression never matched within the specified period. That is evidence to inspect the DOM, timing, frame, or label; increasing the timeout blindly can hide a selector error.
Inspect candidates before clicking
When a partial label is unavoidable, examine every returned handle. For example, collect each candidate’s text content and use a second condition in Python:
Rank #3
- Clear visuals. Fluid motion: A 144Hz refresh rate and 1ms MPRT deliver smooth, tear‑free motion across work, gaming, and streaming for clearer, more fluid viewing.
- Eye comfort: TÜV Rheinland 3‑star* certification reduces harmful blue light while preserving stunning color quality without compromise. *TÜV Rheinland 3-star eye comfort certification.
- Wide viewing angle: Get consistent views across a wide 178° /178° viewing angle.
- In-Plane Switching (IPS): See excellent color accuracy and consistency across wide viewing angles with In-plane Switching (IPS) technology.
- Ultra-thin bezels: Maximize your viewing experience with thin bezels.
candidates = await page.xpath('//button[contains(normalize-space(.), "Save")]')
for index, button in enumerate(candidates):
text = await page.evaluate('(element) => element.textContent', button)
print(index, repr(text.strip()))
if len(candidates) != 1:
raise RuntimeError('The Save label is not unique; refine the XPath')
await candidates[0].click()
Refine the XPath when the output shows several controls. An exact label, a surrounding container, or a stable attribute can make the selector unique. Keeping the match-count assertion in production automation also turns a changed page into a visible failure rather than a silent mis-click.
When the visible wording is not a button’s text
Accessible names and attributes
A control may display an icon while its accessible name is stored in aria-label, or it may carry an explanatory title. In those cases, text matching cannot find the wording because it is not part of the element’s string value. Inspect the actual HTML and adapt the predicate, for example:
buttons = await page.xpath('//button[@aria-label="Open menu"]')
Use an attribute selector only when that attribute is stable and identifies the intended control. If the wording is generated elsewhere, identify the real clickable element instead of forcing a text XPath onto an unrelated node.
Non-button elements
Some interfaces style a link or a div to look like a button. The button-restricted XPath intentionally excludes those elements. If the page genuinely uses another element as the control, change the element test to match the DOM you inspected, then apply the same uniqueness check. Do not broaden the selector to every element containing the word unless that is explicitly what the workflow requires.
XPath or CSS?
Text is a good reason to choose XPath, but it is not always the most stable selector. Use the selector type that reflects the strongest identifier the page exposes.
Free tools Windows power users keep installed
One-click scans. No signup required.
Rank #4
- CURVED FOR ENHANCED ENGAGEMENT: An immersive viewing experience with a curved monitor that wraps more closely around your field of vision; It creates a wider view, enhancing depth perception and minimizing peripheral distraction
- SMOOTH PERFORMANCE FOR SEAMLESS CONTENT: Stay in the action when playing games, watching videos, or working on creative projects; The 100Hz refresh rate reduces lag and motion blur so you don't miss a thing in fast-paced moments¹
- MORE GAMING POWER: Gain the edge with optimizable game settings; Color and image contrast can be adjusted to see scenes more vividly and spot enemies hiding in the dark; Game Mode adjusts any game to fill the screen so you can view every detail²
- KEEP IT EASY ON THE EYES: Care for your eyes and stay comfortable, even during long sessions; Advanced eye comfort technology certified by TÜV reduces eye strain by minimizing blue light and reducing irritating screen flicker²
- INCREASED VERSATILITY: Connect to more; Plug devices straight into your monitor for increased flexibility, making your computing environment even more convenient
| Situation | Preferred selector | Reason |
|---|---|---|
| The label is the only dependable identifier | XPath with normalize-space(.) |
Matches the button’s human-readable wording and includes descendant text. |
A unique id or stable attribute exists |
CSS, such as #submit-button |
Usually simpler and less sensitive to wording or localization. |
| The label is only partly known | XPath with contains(), followed by inspection |
Allows partial matching but requires protection against duplicates. |
| The control is not a native button | CSS or XPath for the actual clickable element | Restricting the expression to button would exclude it. |
Pyppeteer documents both CSS query methods and XPath lookup. A class name that is generated on every build is not more stable merely because it is CSS; choose an identifier that the page’s own markup keeps consistent.
Common failures and precise fixes
Zero matches
- Wrong label: inspect the element’s text content, including punctuation, capitalization, and whitespace.
- Rendered too late: wait for the XPath after navigation or after the action that creates the button.
- Attribute rather than text: use an
aria-labelor other attribute predicate when no text node contains the wording. - Wrong element type: verify whether the clickable node is actually a button.
More than one match
- Partial match is too broad: replace
contains()with equality when possible. - Duplicate responsive controls: a mobile and desktop copy may both exist in the DOM. Add a container or a visibility check after identifying the intended region.
- Hidden template content: inspect each candidate rather than taking index zero.
The click does not produce the expected result
- Confirm that the selected handle is the intended element by printing its text and relevant attributes.
- Check whether another overlay intercepts the click; a successful selector does not guarantee that the control is currently actionable.
- If the click triggers navigation, wait for the resulting page state after clicking rather than assuming the transition is synchronous.
Whitespace or nested markup causes a mismatch
Keep normalize-space(.) and avoid comparing a fragile raw text node. If punctuation or multiple labels are legitimate, use a more specific XPath rather than removing more characters from the comparison.
Reliability and performance practices
XPath evaluation is normally inexpensive compared with launching Chromium and loading the page. The larger reliability gains come from controlling browser lifetime and page state:
- Launch one browser process and reuse it for related pages instead of starting Chromium for every click.
- Set explicit navigation and selector timeouts so a stalled page fails predictably.
- Keep the XPath narrow and assert the expected count on every critical action.
- Log the URL, XPath, match count, and candidate text when a test fails; this makes a changed label distinguishable from a network problem.
- Use a CSS selector when a stable identifier is available, reserving text XPath for cases where wording is genuinely the best signal.
Selectors are tied to the DOM exposed to Pyppeteer. A visual screenshot can show wording that is not represented as a text node, so use the browser’s inspected markup—not pixels—as the source for the expression.
Do not mix Pyppeteer and Playwright syntax
Playwright’s documentation demonstrates role-based locators such as getByRole('button', { name: 'Sign in' }). That API belongs to Playwright; it is not a Pyppeteer method. In Pyppeteer, use page.xpath() or page.Jx() for XPath, or the library’s CSS query methods for CSS selectors.
Best Value
- 【INTEGRATED SPEAKERS】Whether you're at work or in the midst of an intense gaming session, our built-in speakers provide rich and seamless audio, all while keeping your desk clutter-free.
- 【EASY ON THE EYES】 Protect your eyes and enhance your comfort with Blue-Light Shift technology. This feature reduces harmful blue light emissions from your screen, helping to alleviate eye strain during long hours of use and promoting healthier viewing habits.
- 【WIDEN YOUR PERSPECTIVE】Our sleek minimal bezel design ensures undivided attention. The nearly bezel-free display seamlessly connects in a dual monitor arrangement, delivering an unobstructed view that lets you focus on more at once, completely distraction-free.
Or skip the browser setup
If your end goal is a clean image or PDF of the page rather than an in-browser assertion, ScreenshotNeo provides a website screenshot API. It can accept consent banners before capture and remove more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the page verdict and billing status in headers.
For a one-call capture, see the ScreenshotNeo API documentation and run:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
The same request from Python is:
import requests
r = requests.get('https://api.screenshotneo.com/v1/shot', params={'access_key': 'YOUR_API_KEY', 'url': 'https://example.com'}, timeout=90)
open('shot.webp', 'wb').write(r.content)
And from Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo also offers full-page capture with lazy images loaded, element capture by CSS selector, custom JavaScript and CSS, a click-before-capture option, waits for selectors, delays or network idle, device and viewport controls, PDF output, request blocking, custom headers and cookies, signed links, asynchronous jobs, bulk capture, caching with a chosen TTL, usage reporting, and an MCP server with take_screenshot, get_page_info, and capture_pdf tools for AI clients.
Recommended Free Tools
There is no browser setup for this call. Failed loads, bot checks, blank pages, and timeouts are never billed; an MCP server lets AI agents take screenshots; 1,000 screenshots per month are free with no card, and paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.
Frequently Asked Questions
How can I make an XPath text comparison case-insensitive?
XPath 1.0 has no built-in lowercase function. Use translate() to map uppercase letters before comparing, for example translate(normalize-space(.), "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz")="submit". Prefer an exact, case-sensitive label when the page’s capitalization is stable.
How can I avoid clicking a hidden duplicate?
First narrow the XPath to the relevant container. Then inspect each returned handle and use its geometry or state in Python before clicking. A match count of one is necessary, but it does not by itself prove that the element is visible or actionable.
Should localized pages use the English button label?
No. A text selector hard-coded to English will fail when the page renders another locale. Select a stable attribute or localized label supplied by the page, and keep the expected text alongside the locale-specific test data.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

