Zenrows
Talk to sales Start free

What is a CSS selector?

A CSS selector is a pattern that matches elements in a document. Stylesheets use them to decide what to paint; scrapers use the same syntax to decide what to read. .product-card .price means "an element with class price somewhere inside an element with class product-card", whether you are styling it or extracting it.

The syntax you will actually use

Most scraping needs a small subset:

Pattern Matches
div every div
.price class price
#main id main
[data-sku] any element with that attribute
[data-sku="X1"] that attribute with that value
.card .price price at any depth inside card
.card > .price price as a direct child
li:nth-child(2) the second li among its siblings
a[href^="/product/"] href starting with that prefix

The attribute selectors are the most useful and the least used. A data- attribute is usually there because the site's own code depends on it, which makes it far more stable than a class name a build tool generated.

Writing selectors that survive

The instinct is to copy a selector from developer tools. Those are generated to be unique, not durable, and typically look like body > div:nth-child(3) > div > div.sc-a8f2b > span. Every part of that is a dependency on the current layout, and hashed class names such as sc-a8f2b change on the next deploy.

A more durable selector uses the shortest path that is still unambiguous, prefers semantic classes and data- attributes over generated ones, and anchors on text or structure that reflects meaning rather than position. [data-testid="price"] will outlive div.sc-a8f2b > span by years.

Where CSS runs out

CSS selectors move downward and sideways through the tree, never upward. You cannot say "the parent of the element containing this text", and you cannot match on an element's text content at all. Both are routine requirements when scraping, and both are exactly what XPath is for. The blog covers choosing between them in detail.

The failure mode to design against

A selector that matches nothing returns nothing. It does not raise an error. A site redesign therefore turns a working scraper into one that writes empty fields while reporting success, and this is discovered downstream, usually much later.

Assert on the output rather than the request. A record missing a required field is a failure worth alerting on, and that check costs one line.

Where Zenrows fits

The CSS Extractor takes a JSON map of names to selectors and returns matching values as JSON, so extraction happens with the fetch and you get fields instead of a page to parse. It accepts XPath in the same parameter for the cases CSS cannot express, and the advanced selectors guide covers pseudo-classes and combinators for awkward structures.

Go deeper on the blog

In the docs

Last updated: Aug 16, 2026

Get reliable web data in minutes.

Free plan, 5,000 credits every month, no credit card required.