A CSS selector is a pattern that picks elements out of a page. The same selectors that style a page can extract from it. Learn this handful and you can pull almost any field.
| Selector | Matches |
|---|---|
| p, a | Every element of that tag |
| .price | Every element with that class |
| #featured | The one element with that id |
| .card.sale | Elements with BOTH classes (no space = AND) |
| .card .price | A .price anywhere inside a .card (space = descendant) |
| .card > .title | A .title that is a DIRECT child of .card |
| h4 + p | The p immediately after an h4 (adjacent sibling) |
| [href^="/x"] | Attribute starts-with (^= starts, $= ends, *= contains) |
| tr:nth-child(even) | By position among siblings |
| .plan:not(.featured) | Everything matching, except a case you exclude |
The biggest beginner mistake is the space. .card.sale means ONE element carrying both classes; .card .sale means a .sale somewhere inside a .card. They behave completely differently.
Write selectors that survive a redesign
- Prefer stable class or data-* names over positional chains: .product-card .price survives edits that break .list > div:nth-child(2) > span.
- Avoid the browser "Copy selector" — it generates brittle, positional paths tied to the exact current layout.
- A selector is only as stable as the HTML behind it; when a site is redesigned, expect to update it. That is the main maintenance cost of scraping.
Tip · Do not just read this — the Scraping Lab at /scraping has 12 interactive challenges where you type a selector and see exactly what it matches (green = right, red = wrong), plus a 26-question quiz.