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 page.locator('div') to create a locator for every <div> on the page, then call count() for the current number of matches. For extraction, use allInnerTexts(), allTextContents(), or evaluateAll() when you need custom fields. In tests that assert a number, prefer the retrying expect(locator).toHaveCount() assertion so Playwright waits for the page to reach the expected state.
This guide shows reliable TypeScript patterns, explains rendered text versus DOM text, handles dynamic lists, and documents the failure modes that make broad div selectors flaky.
Selecting every div
A tag selector is the clearest choice when the element type itself is the requirement:
const divs = page.locator('div');
A locator is a live description of matching elements. It is not a one-time array, so Playwright can resolve it again after the DOM changes. The selector may match zero, one, or many elements.
#1 Best Overall
Count the current matches
const count = await divs.count();
console.log(`Found ${count} div elements`);
count() returns the number of elements that match at the moment it is called. It is useful for diagnostics or for branching logic. It does not, by itself, wait for an application to finish rendering.
Assert an expected count
For a test assertion, use a web-first assertion:
await expect(divs).toHaveCount(3);
toHaveCount() retries until the expected count is observed or the assertion timeout expires. This is safer than reading count() once and comparing the returned number while a list is still loading. The expected value above is illustrative; derive it from the page contract you are testing.
Extract text from all matching divs
Rendered text with allInnerTexts()
const visibleTexts = await divs.allInnerTexts();
console.log(visibleTexts);
allInnerTexts() returns an array based on each element’s innerText. It is generally the right choice when your test or scraper needs text as a user would see it, including rendering-related whitespace behavior.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →DOM text with allTextContents()
const domTexts = await divs.allTextContents();
console.log(domTexts);
allTextContents() returns an array based on each node’s textContent. It includes text in descendants regardless of whether CSS makes that text visible. Use it when the DOM representation is the data source, such as hidden labels or template content.
| Method | Returns | Use it when |
|---|---|---|
allInnerTexts() |
Array of rendered innerText values |
You need user-visible text and layout-aware whitespace |
allTextContents() |
Array of DOM textContent values |
You need text present in the DOM, including hidden descendants |
Extract custom data with evaluateAll()
When text alone is insufficient, evaluateAll() runs a mapping function in the page context and passes the matched elements as an array:
Rank #2
const rows = await divs.evaluateAll(elements =>
elements.map(element => ({
text: element.textContent,
id: element.id,
className: element.className,
}))
);
console.log(rows);
This pattern is suitable for attributes, dataset values, nested links, or a normalized object assembled from several descendants. Keep the callback serializable: return plain objects, arrays, and primitive values rather than DOM nodes.
Extract attributes and nested values
const cards = page.locator('div[data-card]');
const data = await cards.evaluateAll(elements =>
elements.map(card => ({
key: card.getAttribute('data-card'),
heading: card.querySelector('h2')?.textContent?.trim() ?? null,
href: card.querySelector('a')?.getAttribute('href') ?? null,
}))
);
A narrower selector such as div[data-card] prevents unrelated layout containers from entering your result set.
Free tools Windows power users keep installed
One-click scans. No signup required.
A complete Playwright test
import { test, expect } from '@playwright/test';
test('count and read divs', async ({ page }) => {
await page.goto('https://example.com');
const divs = page.locator('div');
await expect(divs).toHaveCount(3);
const texts = await divs.allTextContents();
console.log(texts);
});
Install and configure Playwright in your project, then run the test with your normal Playwright command. Replace the illustrative URL and count with the page and contract under test.
Choose a locator that survives UI changes
A literal tag selector is appropriate when every div is relevant, but most pages use div for layout. A broad selector can therefore count wrappers, navigation shells, analytics containers, and unrelated components.
Prefer meaning over DOM shape
For non-interactive content, Playwright supports text locators when visible wording identifies the target. For buttons, links, checkboxes, and other controls, prefer role locators with an accessible name. User-facing attributes or explicit test IDs are also good contracts. These choices are less coupled to nesting and CSS classes than long CSS or XPath chains.
Rank #3
const priceCards = page.getByTestId('price-card');
const notice = page.getByText('Free trial');
const submit = page.getByRole('button', { name: 'Submit' });
If the application has no stable user-facing contract, ask developers to add a dedicated test ID rather than encoding a fragile path such as main > div:nth-child(2) > section > div.
Recommended Free Tools
Scope a tag selector
const dialogDivs = page.getByRole('dialog').locator('div');
const productDivs = page.locator('[data-testid="product-grid"] div');
Scoping reduces accidental matches while retaining the simple tag selector inside the relevant component.
Dynamic content and timing
Single reads are vulnerable to race conditions when JavaScript adds, removes, or replaces nodes. Establish a meaningful ready condition before collecting a snapshot.
Wait for a component, not an arbitrary sleep
const list = page.getByTestId('results');
await expect(list).toBeVisible();
const items = list.locator('div[data-item]');
await expect(items).toHaveCount(10);
const texts = await items.allInnerTexts();
Waiting for a selector or assertion ties the test to application behavior. A fixed waitForTimeout() can be too short on a slow run and unnecessarily long on a fast one.
Understand locator.all()
locator.all() immediately returns locators for elements currently present. It does not wait for the list to reach a particular count or finish loading. On a changing list, the returned collection can represent a transient state. Use a readiness assertion first, then call bulk extraction methods.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →Assert text without reading too early
await expect(items).toHaveText([
'First result',
'Second result',
]);
For an assertion, toHaveText() retries and reports a useful mismatch. Extract with allInnerTexts() after the state is stable when you need the values for logging or further processing.
Strictness: bulk operations versus single-element operations
Bulk methods such as count(), allInnerTexts(), allTextContents(), and evaluateAll() are designed for multiple matches. Operations that imply one target are strict and throw if the locator resolves to more than one element.
const divs = page.locator('div');
// Valid for a collection:
const n = await divs.count();
// Strict: fails if several divs match:
// await divs.textContent();
If you intend one element, narrow the locator or select deliberately with first(), last(), or nth(index). Use those positional methods only when order is part of the page contract; otherwise a semantic locator is more resilient.
Common failures and fixes
The count is zero
- Cause: the content is inside an iframe. Fix: obtain a frame locator, then select inside it, for example
page.frameLocator('iframe').locator('div'). - Cause: the application has not rendered the component. Fix: wait for a stable marker with
expect(...).toBeVisible()ortoHaveCount(). - Cause: the target is inside shadow DOM or a different browsing context. Fix: inspect the component boundary and use the appropriate locator or frame.
The count is much larger than expected
- Cause: layout uses many wrapper
divelements. Fix: scope the locator and add a semantic attribute, role, text, or test ID. - Cause: hidden templates or duplicated responsive markup are included. Fix: decide whether DOM presence or visible content is required, then choose
allTextContents()orallInnerTexts()accordingly and filter with a meaningful selector.
Text is empty or differs from what the browser shows
- Cause: you selected
textContentsemantics but the visible text is generated elsewhere or hidden. Fix: tryallInnerTexts()for rendered text, or inspect descendants and attributes withevaluateAll(). - Cause: whitespace and nested nodes differ. Fix: normalize deliberately in your mapping function instead of assuming the two APIs are interchangeable.
An assertion is flaky
Replace a one-time count() comparison with await expect(locator).toHaveCount(expected), and wait on the component’s meaningful loaded state before extracting. Avoid arbitrary sleeps and selectors tied to incidental nesting.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Performance, reliability, and data quality
Bulk extraction is usually simpler and less chatty than looping over every element and issuing separate calls. If you only need one field, map that field in a single evaluateAll(). If you need a small, stable subset, narrow the locator first; reducing matches also reduces the amount of data serialized back to the test process.
For very large pages, avoid selecting every div unless that is genuinely the requirement. A page-wide locator can include thousands of nodes and make both assertions and returned arrays harder to interpret. Component-scoped locators document intent and are less likely to change when a framework adds a wrapper.
Keep extraction deterministic: wait for the same readiness signal on every run, define whether hidden text counts, and assert the contract before collecting a diagnostic snapshot. When a count is expected to vary by data, assert a lower-level invariant (for example, that the results container exists) and treat the returned count as data rather than a fixed test expectation.
Or skip the browser setup
If your goal is a rendered page image rather than DOM-level assertions, ScreenshotNeo returns a screenshot or PDF from one request. Its cleanup step accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be disabled. Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. It also provides an MCP server for Claude, Cursor, and other MCP clients, with take_screenshot, get_page_info, and capture_pdf tools.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteUse the API documentation at https://screenshotneo.com/docs/ for authentication and options. A minimal call is:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Options include full-page capture with lazy images, CSS-selector element capture, dark mode, device presets or custom viewports, retina scale, PDF paper and page-range settings, custom CSS and JavaScript, pre-capture clicks, selector hiding, waits for selectors, delays or network idle, request and resource blocking, custom headers/cookies/user agents, authorization, timezone and geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous jobs with signed webhooks, bulk capture for up to 100 URLs per call, a usage API, an OpenAPI specification, and compatible parameter names used by other screenshot APIs.
The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; yearly billing gives two months free, and every feature is available on every plan. Create a free ScreenshotNeo account to start.
Frequently Asked Questions
Can I count only visible div elements?
A tag locator includes matching DOM elements whether or not they are visible. Scope to the component you need and use rendered-text extraction or an explicit visibility filter when visibility is part of your requirement.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minuteShould I use CSS or XPath for div extraction?
Use a simple CSS tag or attribute selector when it expresses the contract. Prefer semantic text, role, or test-ID locators when available; long CSS and XPath chains that encode DOM structure are more brittle.
How do I handle divs inside an iframe?
Create a frame locator for the iframe and then locate inside it, such as page.frameLocator('iframe').locator('div'). A page-level locator cannot see elements in a separate frame.
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.

