     [Blog](https://scrapfly.io/blog)   /  [css-selectors](https://scrapfly.io/blog/tag/css-selectors)   /  [Ultimate CSS Selector Cheatsheet for Web Scraping and HTML Parsing](https://scrapfly.io/blog/posts/css-selector-cheatsheet)   # Ultimate CSS Selector Cheatsheet for Web Scraping and HTML Parsing

 by [Bernardas Alisauskas](https://scrapfly.io/blog/author/bernardas) Apr 18, 2026 24 min read [\#css-selectors](https://scrapfly.io/blog/tag/css-selectors) [\#data-parsing](https://scrapfly.io/blog/tag/data-parsing) 

 [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fcss-selector-cheatsheet "Share on LinkedIn")    

 

 

      

CSS selectors is a powerful HTML querying protocol which is used by browsers to determine what HTML elements to style. It's also incredibly useful in HTML parsing when web scraping or processing HTML data, as the same queries can be used to select values as well.

In web scraping, CSS selectors are an easy and powerful way to parse HTML data and are used in many web scraping libraries. This article is a carefully curated CSS Selector cheatsheet for web scraping, though it can apply to any HTML parsing tasks.

## Key Takeaways

CSS selectors are essential for web scraping, allowing you to precisely locate and extract data from HTML documents. Master these techniques with our comprehensive cheatsheet covering navigation, attribute matching, pseudo-selectors, and practical web scraping workflows.

- Use navigation selectors (&gt;, space, ~, +) to traverse HTML document structure and target nested data like product details or article content
- Match attributes with \[attr\], \[attr=value\], and \[attr\*=value\] patterns for flexible element targeting in dynamic web pages
- Leverage pseudo-selectors like :nth-child(), :first-child, and :last-child for position-based selection when scraping lists and tables
- Combine selectors with commas for multiple element selection and complex data extraction queries
- Apply CSS selectors in popular web scraping libraries like BeautifulSoup, parsel, Scrapy, and Selenium for efficient data extraction

[Parsing HTML with CSS SelectorsIntroduction to using CSS selectors to parse web-scraped content. Best practices, available tools and common challenges by interactive examples.](https://scrapfly.io/blog/posts/parsing-html-with-css)

**Get web scraping tips in your inbox**Trusted by 100K+ developers and 30K+ enterprises. Unsubscribe anytime.





## CSS Selectors for Web Scraping

CSS selectors were originally designed for styling web pages, allowing developers to apply visual rules to specific HTML elements. However, the same powerful syntax that makes CSS selectors excellent for styling also makes them invaluable for **web scraping and data extraction**.

When scraping websites, you need a reliable way to locate and extract specific pieces of data from HTML documents. Rather than using fragile string parsing or complex regular expressions, CSS selectors provide an elegant, declarative approach to pinpointing exactly the elements you need. Whether you're extracting product prices, article titles, user reviews, or any other structured data, CSS selectors help you write precise, maintainable extraction logic.

Modern web scraping libraries like [BeautifulSoup](https://pypi.org/project/beautifulsoup4/), [parsel](https://pypi.org/project/parsel/), [Scrapy](https://scrapy.org/), and browser automation tools like [Selenium](https://www.selenium.dev/) and [Playwright](https://playwright.dev/) all support CSS selectors as a primary method for element selection. This means learning CSS selectors once gives you a transferable skill across virtually all web scraping tools and frameworks.

The key advantage of CSS selectors for web scraping is their readability and precision. A selector like `.product-card .price` immediately communicates intent: "find the price element inside product cards." This clarity makes scraping code easier to write, debug, and maintain compared to XPath or regex alternatives.

## CSS Selectors in the Web Scraping Workflow

Understanding where CSS selectors fit in the overall web scraping process helps you use them more effectively. Here's how a typical scraping workflow operates:

**Step 1: Send HTTP Request**
Your scraper sends an HTTP request to the target website, requesting the webpage you want to extract data from. This is handled by libraries like `requests` in Python or `fetch` in JavaScript.

**Step 2: Receive HTML Response**
The server responds with the raw HTML source code of the page. This is the document you'll be parsing.

**Step 3: Parse HTML into DOM**
The HTML string is parsed into a Document Object Model (DOM) tree structure, where each HTML element becomes a node that can be queried and traversed.

**Step 4: Use CSS Selectors to Target Elements** ⭐
This is where CSS selectors shine. Instead of searching through raw HTML text, you use elegant selectors to precisely target the data you need:

- `.product-title` - Select all product titles
- `.price-amount` - Select price values
- `.product-card a[href]` - Select all links within product cards
- `table.data-table tr:nth-child(n+2) td` - Select table cells, skipping the header row

**Step 5: Extract Data**
Once you've selected the right elements, extract the data you need: text content, attribute values (like `href` or `src`), or even the HTML structure itself.

**Step 6: Structure and Store**
Finally, organize the extracted data into your desired format (JSON, CSV, database records) for further processing or analysis.

CSS selectors are the bridge between raw HTML and structured data. With [Scrapfly's web scraping API](https://scrapfly.io/web-scraping-api), steps 1-3 are handled automatically, including JavaScript rendering and anti-bot bypass. You focus on step 4 (writing CSS selectors), and Scrapfly returns clean, parseable HTML ready for extraction.

## Finding CSS Selectors with Browser Developer Tools

One of the most practical skills for web scraping is knowing how to find and test CSS selectors using your browser's built-in Developer Tools. This section walks you through the complete workflow.

### Inspecting Elements to Find Selectors

1. **Open Developer Tools**: Press `F12` (or `Cmd+Option+I` on Mac) to open DevTools, or right-click any element and select "Inspect"
2. **Navigate to the Element**: In the Elements panel (Chrome/Edge) or Inspector panel (Firefox), you'll see the DOM tree. Hover over elements to highlight them on the page, or right-click the specific element you want to scrape and choose "Inspect"
3. **Copy the CSS Selector**: Right-click on the highlighted HTML element in the DOM tree, then select **Copy → Copy selector**. This gives you an auto-generated CSS selector
4. **Simplify the Selector**: Browser-generated selectors are often overly specific, like:
    
    css```css
    #root > div > main > section:nth-child(2) > div > article > h2
    ```
    
    
    
    Look for simpler alternatives using class names, IDs, or data attributes:
    
    css```css
    article h2
    .article-title
    [data-testid="article-title"]
    ```

### Testing Selectors in the Browser

Before using selectors in your scraping code, test them directly in the browser. There are two effective methods:

**Method 1: DOM Search (Recommended)**
In the Elements panel, press `Ctrl+F` (or `Cmd+F` on Mac) to open the search box. Type your CSS selector and the browser will highlight all matching elements and show the match count. This is the fastest way to verify your selector works.

**Method 2: Console Commands**
Open the Console panel and use JavaScript to test selectors:

javascript```javascript
// Find first matching element
document.querySelector('.product-price')

// Find ALL matching elements (returns array-like NodeList)
document.querySelectorAll('.product-card')

// Shorthand for querySelectorAll (Chrome/Firefox)
$$('.product-card .title')
```



### Tips for Creating Robust Selectors

Web pages change frequently, so creating stable selectors is crucial for maintainable scrapers:

- **Prefer semantic class names**: `.product-title` is more stable than `.css-1a2b3c` (auto-generated)
- **Use data attributes when available**: Many sites use `data-testid`, `data-id`, or similar attributes that are less likely to change
- **Avoid overly long selector chains**: `div > div > div > span` will break easily; look for a unique class or ID closer to your target
- **Combine element type with class**: `h2.title` is more specific than just `.title` without being fragile
- **Test with multiple items**: Make sure your selector captures all the items you need, not just the first one

### Real Example: Finding Product Prices

Let's walk through finding a selector for product prices on an e-commerce page:

1. Right-click on a price and select "Inspect"
2. The DevTools highlights something like: `<span class="price-current">$299.99</span>`
3. Try the selector `.price-current` in the DOM search (`Ctrl+F`)
4. Verify it matches all product prices on the page (check the match count)
5. If there are false positives, refine to `.product-card .price-current`

With practice, this workflow becomes second nature, allowing you to build scrapers quickly and confidently.



[🗋⮭](#cheatsheet "go to cheatsheet")This CSS selector cheatsheet contains all selector features you need for web scraping and HTML parsing. Whether you're extracting product data, article content, or any structured information from websites, these selectors will help you target exactly what you need.
Clicking on the explanation text will take you to a real-life interactive example with more details. Note that CSS selectors can differ in different implementations, so unique non-standard features are marked as such.

## Cheatsheet

| Selector | Explanation |
|---|---|
|  | **Navigation** |
| &gt; | [selects direct child](#direct-child) |
| ` ` (space) | [selects any descendant](#any-descendant) |
| ~ | [selects following sibling](#any-following-sibling) |
| + | [selects direct following sibling](#any-following-sibling) |
| , | [separator for joined selectors](#joining-selectors) |
|  | **Attribute Matching** |
| . | [selects by class](#by-class) |
| \# | [selects by id](#by-id) |
| \[\] | [attribute selector](#by-attribute) |
| \[attr\] | [select elements that have attribute present](#by-attribute) (even if it's empty) |
| \[attr=value\] | [match exact attribute value](#by-attribute-value) |
| \[attr=value i\] | [`i` suffix turns any attribute match case insensitive](#by-case-insensitive-attribute-value)\* |
| \[attr\*=value\] | [match containing attribute value](#by-partial-attribute-value) |
| \[attr\|=value\] | [match exact ignoring "-suffixes" value](#by-attribute-value-ignoring-minus-suffix) |
| \[attr^=value\] | [match attributes that start with value](#by-attribute-value-starting-with) |
| \[attr$=value\] | [match attributes that end with value](#by-attribute-value-ending-with) |
| \[attr~=value\] | [match attributes that contain a word](#by-attribute-containing-word) |
|  | **Element Matching** |
| :not() | [reverses selection](#reversing-matchers-using-not) |
| :has() | [select if element has a matching descendant](#has-descendant) |
| :is() | [apply multiple selectors](#is-matcher) |
| :first-child | [select if it's the first element in the group](#first-child) |
| :last-child | [select if it's the last element in the group](#last-child) |
| :nth-child() | [select if it's the Nth element, supports `even`, `odd`](#nth-child) |
| :nth-last-child() | [like `nth-child` but reversed](#nth-last-child) |
| :first-of-type | [select if it's the first element of that type in the group.](#first-of-type) |
| :last-of-type | [select if it's the last element of that type in the group.](#last-of-type) |
| :nth-of-type() | [select if it's the Nth element of that type in the group.](#nth-of-type) |
| :only-of-type() | [select if it's the only element of that type in the group.](#only-of-type) |
|  | **Non-standard Functions** |
| ::attr(name) | [select attribute value.](#getting-attribute-value) Available in [scrapy](https://pypi.org/project/Scrapy/), [parsel](https://pypi.org/project/parsel/), [Scrapfly SDK](https://scrapfly.io/docs/sdk/python) |
| :text | [select text value.](#getting-element-text) Available in [scrapy](https://pypi.org/project/Scrapy/), [parsel](https://pypi.org/project/parsel/), [Scrapfly SDK](https://scrapfly.io/docs/sdk/python) |

*\* limited availability*

What CSS selectors **cannot** do:

- Select **preceding siblings**.
- Select **parent** or **ancestor** elements.
- Select array **slices**.
- Select by **text** value.
- Select by **element count**.
- Select by **element depth**.

These features are, however available in [Parsing HTML with Xpath](https://scrapfly.io/blog/posts/parsing-html-with-xpath) selector engine.

## Direct Child

&lt;div&gt; &lt;p &gt; Follow us on &lt;a href="https://x.com/@scrapfly\_dev"&gt;X!&lt;/a&gt; &lt;skip&gt;ignore&lt;/skip&gt; &lt;/p&gt; &lt;/div&gt; The `>` direct child selector selects only direct children of the parent element. Here, the `a` element is selected as it's a direct child of `p` and `div`. In web scraping, this selector is essential for targeting specific elements like `.product > .title` to get product titles without accidentally selecting nested review titles. Note that this selector can be dangerous as HTML tree depth can change easily, breaking the selector. For example, if the `a` element is wrapped in `span` the selector will break.

## Any Descendant

&lt;div&gt; &lt;p &gt; Follow us on &lt;a href="https://x.com/@scrapfly\_dev"&gt;X!&lt;/a&gt; &lt;skip&gt;ignore&lt;/skip&gt; &lt;/p&gt; &lt;/div&gt; Space selects any descendant no matter how many layers deep. Here, the `a` element is selected as it's a descendant of `div`. This is especially useful in web scraping when you need to find elements regardless of how deeply nested they are in the page structure.

## Any Following Sibling

&lt;article&gt; &lt;p&gt;ignore&lt;/p&gt; &lt;p class="ad"&gt;ignore&lt;/p&gt; &lt;p&gt;select&lt;/p&gt; &lt;p&gt;select&lt;/p&gt; &lt;/article&gt; The `~` selects any following general sibling no matter how many layers deep. Here, the `p` elements are selected as they are following siblings of `.ad`.

## Direct Following Sibling

&lt;article&gt; &lt;p&gt;ignore&lt;/p&gt; &lt;p class="ad"&gt;ignore&lt;/p&gt; &lt;p&gt;select&lt;/p&gt; &lt;p&gt;ignore&lt;/p&gt; &lt;/article&gt; The `+` selects one following adjacent sibling (i.e. has to be right below it). Here, the first `p` element is selected as it's a direct following sibling of `.ad`.

## Joining Selectors

&lt;div&gt; &lt;article&gt; &lt;p&gt;select paragraph&lt;/p&gt; &lt;div&gt; &lt;div&gt;ignore&lt;/div&gt; &lt;p&gt;select nested paragraph&lt;/p&gt; &lt;/div&gt; &lt;span&gt;select span&lt;/span&gt; &lt;a&gt;select link&lt;/a&gt; &lt;div&gt;ignore&lt;/div&gt; &lt;/article&gt; &lt;/div&gt; Selectors can be joined with `,` to select multiple elements. Here, the `p`, `span` and `a` elements are selected. Note that the result order usually follows the structure of the HTML tree.

## by Class

&lt;div&gt; &lt;div class="product"&gt;select&lt;/div&gt; &lt;div class="sold product"&gt;select&lt;/div&gt; &lt;div class="sold product new"&gt;select&lt;/div&gt; &lt;div class="product-2"&gt;ignore&lt;/div&gt; &lt;/div&gt; The `.` selector can be used to restrict the selection to elements that contain the class value in the `class` attribute. Here, the `div` elements with `product` in the `class` attribute are selected. Class selectors are the workhorses of web scraping. Most modern websites use semantic class names like `.product-card`, `.price`, `.article-title` that make data extraction straightforward.

## by ID

&lt;div&gt; &lt;div id="product"&gt;select&lt;/div&gt; &lt;div id="sold product"&gt;select&lt;/div&gt; &lt;div id="sold product new"&gt;select&lt;/div&gt; &lt;div id="product-2"&gt;ignore&lt;/div&gt; &lt;/div&gt; ## by Attribute

&lt;div&gt; &lt;a href="#"&gt;enabled link&lt;/a&gt; &lt;a&gt;disabled link&lt;/a&gt; &lt;a href=""&gt;enabled link&lt;/a&gt; &lt;/div&gt; Square brackets (`[]`) can be used to match elements by attribute values. For example, `[href]` matches any element that has `href` attribute (even if it's empty). This is incredibly useful for web scraping when you need to extract all links from navigation menus or article listings using selectors like `nav a[href]` or `.article-list a[href]`.

## by Attribute Value

&lt;div&gt; &lt;span data-item="product"&gt;select&lt;/span&gt; &lt;div data-item="product"&gt;select&lt;/div&gt; &lt;span data-item="product-new"&gt;ignore&lt;/span&gt; &lt;/div&gt; Attributes can be matched exactly using `attrib=value` syntax. Note that this is case-sensitive.

## by Case Insensitive Attribute Value

&lt;div&gt; &lt;span data-item="PRODUCT"&gt;select&lt;/span&gt; &lt;div data-item="Product"&gt;select&lt;/div&gt; &lt;div data-item="product"&gt;select&lt;/div&gt; &lt;span data-item="product-new"&gt;ignore&lt;/span&gt; &lt;/div&gt; Any attribute matcher can be made case-insensitive by adding `i` suffix. Here, the `span` and `div` elements are selected as they match the `data-item` attribute value case-insensitively.

## by Partial Attribute Value

&lt;div&gt; &lt;a href="social-link.com"&gt;select&lt;/a&gt; &lt;a href="social-link2.com"&gt;select&lt;/a&gt; &lt;a href="ignore"&gt;ignore&lt;/a&gt; &lt;/div&gt; The `*=` will match when attribute contains the supplied value anywhere in the value string.

## by Attribute Value Ignoring Minus Suffix

&lt;div&gt; &lt;a class="important-link"&gt;select&lt;/a&gt; &lt;a class="important-url"&gt;select&lt;/a&gt; &lt;a class="important"&gt;select&lt;/a&gt; &lt;a class="foo important-item"&gt;doesn't begin exactly&lt;/a&gt; &lt;a class="important item"&gt;contains more than just match&lt;/a&gt; &lt;a class="importantitem"&gt;doesn't match&lt;/a&gt; &lt;/div&gt; The `|=` selector is unique and matches only when value matches exactly or has a trailing `-suffix`.

## by Attribute Value Starting With

&lt;div&gt; &lt;a class="dataname"&gt;select&lt;/a&gt; &lt;a class="data-age"&gt;select&lt;/a&gt; &lt;a class="data extra"&gt;select&lt;/a&gt; &lt;a class="foo data"&gt;ignore&lt;/a&gt; &lt;/div&gt; The `^=` selector matches when attribute value starts with the supplied value exactly.

## by Attribute Value Ending With

&lt;div&gt; &lt;a class="name-data"&gt;select&lt;/a&gt; &lt;a class="age data"&gt;select&lt;/a&gt; &lt;a class="data"&gt;select&lt;/a&gt; &lt;a class="data foo"&gt;ignore&lt;/a&gt; &lt;/div&gt; The `$=` selector matches when attribute value ends with the supplied value exactly.

## by Attribute Containing Word

&lt;div&gt; &lt;a class="data"&gt;select&lt;/a&gt; &lt;a class="foo data"&gt;select&lt;/a&gt; &lt;a class="foo data bar"&gt;select&lt;/a&gt; &lt;a class="datafoo"&gt;ignore&lt;/a&gt; &lt;a class="data-bar"&gt;ignore&lt;/a&gt; &lt;/div&gt; The `~=` selector matches when attribute value contains the supplied value as a word. A word is defined as a string of characters delimited by spaces.

## Reversing Matchers Using Not

&lt;div&gt; &lt;a class="foo"&gt;select&lt;/a&gt; &lt;a class="ignore"&gt;ignore&lt;/a&gt; &lt;a class="bar"&gt;select&lt;/a&gt; &lt;a class="data"&gt;select&lt;/a&gt; &lt;a class="ignore"&gt;ignore&lt;/a&gt; &lt;/div&gt; The `:not()` pseudo selector follows node selector and will reverse any matcher like `.class`, `#id` or attribute matchers like `[attribute=ignore]`.

## First Child

&lt;div&gt; &lt;div class="products"&gt; &lt;a&gt;select&lt;/a&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;/div&gt; &lt;div class="products"&gt; &lt;a&gt;select&lt;/a&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;/div&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;/div&gt; The `:first-child` pseudo selector will select only the elements that are first children in their group of all siblings. In other words, first element in the group.

## Last Child

&lt;div&gt; &lt;div class="products"&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;a&gt;select&lt;/a&gt; &lt;/div&gt; &lt;div class="products"&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;a&gt;select&lt;/a&gt; &lt;/div&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;/div&gt; The `:last-child` pseudo selector will select only the elements that are last children in their group of all siblings. In other words, last element in the group.

## Nth Child

&lt;div&gt; &lt;div class="products"&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;a&gt;select&lt;/a&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;/div&gt; &lt;div class="products"&gt; &lt;div&gt;ignore&lt;/div&gt; &lt;a&gt;select&lt;/a&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;/div&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;/div&gt; The `:nth-child` pseudo selector will select only the elements that are Nth children in their group of all siblings. In other words, Nth element in the group. It also supports special values like `even` and `odd` - try them!

## Nth Last Child

&lt;div&gt; &lt;div class="products"&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;a&gt;select&lt;/a&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;/div&gt; &lt;div class="products"&gt; &lt;div&gt;ignore&lt;/div&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;a&gt;select&lt;/a&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;/div&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;/div&gt; The `:nth-last-child` pseudo selector is just `:nth-child` selector but reversed. In the example above we're selecting 2nd to last element in the group.

## First Of Type

&lt;div&gt; &lt;div class="products"&gt; &lt;a&gt;select&lt;/a&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;/div&gt; &lt;div class="products"&gt; &lt;div&gt;ignore&lt;/div&gt; &lt;a&gt;select&lt;/a&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;/div&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;/div&gt; The `:first-of-type` pseudo selector will select the first element of given type. It's similar to `:first-child` but instead of considering all siblings, it considers only siblings of the same node type.

## Last Of Type

&lt;div&gt; &lt;div class="products"&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;a&gt;select&lt;/a&gt; &lt;/div&gt; &lt;div class="products"&gt; &lt;div&gt;ignore&lt;/div&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;a&gt;select&lt;/a&gt; &lt;/div&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;/div&gt; The `:last-of-type` pseudo selector will select the last element of given type. It's similar to `:last-child` but instead of considering all siblings, it considers only siblings of the same node type.

## Nth Of Type

&lt;div&gt; &lt;div class="products"&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;a&gt;select&lt;/a&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;/div&gt; &lt;div class="products"&gt; &lt;div&gt;ignore&lt;/div&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;a&gt;select&lt;/a&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;/div&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;/div&gt; The `:nth-of-type` pseudo selector will select elements of given type that are Nth element in their group. It's similar to `:first-of-type` and `:last-of-type` just more flexible as index can be specified. It also supports special values like `even` and `odd` - try them!

## Only of Type

&lt;div&gt; &lt;div class="products"&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;/div&gt; &lt;div class="products"&gt; &lt;span&gt;ignore&lt;/span&gt; &lt;a&gt;select&lt;/a&gt; &lt;span&gt;ignore&lt;/span&gt; &lt;/div&gt; &lt;a&gt;ignore&lt;/a&gt; &lt;/div&gt; The `:only-of-type` pseudo selector will select elements of given type that are the only element of said type in their group.

## Has Descendant

&lt;article&gt; &lt;div&gt; &lt;a class="product"&gt;select&lt;/a&gt; &lt;a&gt;select&lt;/a&gt; &lt;/div&gt; &lt;div&gt; &lt;div class="wrapper"&gt; &lt;a class="product"&gt;select&lt;/a&gt; &lt;a&gt;select&lt;/a&gt; &lt;/div&gt; &lt;/div&gt; &lt;div&gt; &lt;a class="advertisement"&gt;ignore&lt;/a&gt; &lt;div&gt;ignore&lt;/div&gt; &lt;/div&gt; &lt;/article&gt; The `:has()` pseudo selector is a way of selecting a parent element based on the existence of a certain child. Here, the `div` elements that have a child with `product` class are selected. Note that using any descendant selector (space) can cause a lot of duplicate results so using the direct child selector (`>`) is recommended. Try removing the `>` to see the difference.

## Is Matcher

&lt;article&gt; &lt;div class="product"&gt;select&lt;/div&gt; &lt;span class="product foo"&gt;select&lt;/span&gt; &lt;p class="product"&gt;ignore&lt;/p&gt; &lt;/article&gt; The `:is()` pseudo selector is a way of selecting elements that match any of the supplied selectors. Here, the `div` and `span` elements are selected as they match the `:is()` selector. This pseudo selector can be very powerful when combined with `:not` - try to exclude `.foo` from the selection.

## Getting Attribute Value

&lt;article&gt; &lt;a href="some url1"&gt;select&lt;/a&gt; &lt;a href="some url2"&gt;select&lt;/a&gt; &lt;span href="some url2"&gt;ignore&lt;/span&gt; &lt;/article&gt; The `::attr()` is a non-standard pseudo selector used in tools like [scrapy](https://scrapfly.io/page:posts/web-scraping-with-scrapy), [parsel](https://pypi.org/project/parsel/), and [Scrapfly SDK](https://scrapfly.io/docs/sdk/python) to select element attribute exclusively.

## Getting Element Text

&lt;article&gt; &lt;a href="some url1"&gt;select&lt;div&gt;select-nested&lt;/div&gt;&lt;/a&gt; &lt;a href="some url2"&gt;select&lt;/a&gt; &lt;span href="some url2"&gt;ignore&lt;/a&gt; &lt;/article&gt; The `::text` is a non-standard pseudo selector used in tools like [Web Scraping With Scrapy: The Complete Guide in 2026](https://scrapfly.io/blog/posts/web-scraping-with-scrapy#creating-spiders), [parsel](https://pypi.org/project/parsel/) and [Scrapfly SDK](https://scrapfly.io/docs/sdk/python) to select element text directly.

## CSS Selectors vs XPath: Which to Use for Web Scraping?

Both CSS selectors and XPath are powerful tools for selecting elements in HTML documents, but they have different strengths. Here's a detailed comparison to help you choose the right tool for your web scraping needs:

| Feature | CSS Selectors | XPath |
|---|---|---|
| **Browser Performance** | Faster (native browser support) | Slower |
| **Navigate Up DOM** | Cannot select parent elements | Can traverse backwards (`/..`) |
| **Select by Text Content** | Limited (`:contains()` non-standard) | Full text matching (`text()`, `contains()`) |
| **Syntax Readability** | Cleaner, more concise | More verbose but more expressive |
| **Learning Curve** | Easier for web developers | Steeper learning curve |
| **Sibling Selection** | Following siblings only (`~`, `+`) | Any sibling direction |
| **Complex Conditions** | Limited | Full boolean logic (`and`, `or`) |

### When to Use CSS Selectors

Choose CSS selectors when:

- You're already familiar with CSS syntax from web development
- Elements have good class or ID attributes for targeting
- You only need forward navigation (parents → children, following siblings)
- Performance is critical (CSS selectors are faster in browsers)
- You want cleaner, more readable extraction code

### When to Use XPath

Choose XPath when:

- You need to select parent or ancestor elements (CSS can't do this)
- You're selecting elements by their text content (e.g., "find the link containing 'Next Page'")
- Complex attribute logic is required (e.g., multiple conditions)
- Working with XML documents (not just HTML)
- The HTML structure requires backward traversal

### Practical Example

Selecting all links inside elements with class "product":

css```css
/* CSS Selector */
.product a[href]
```



xpath```xpath
(: XPath equivalent :)
//div[@class="product"]//a[@href]
```



Selecting parent of an element (XPath only):

xpath```xpath
(: Find the parent div of elements with class 'price' :)
//span[@class="price"]/parent::div
```



For a comprehensive guide to XPath selectors, see our [XPath Cheatsheet](https://scrapfly.io/blog/posts/parsing-html-with-xpath).



## FAQ

What are the main differences between CSS selectors and XPath for web scraping?CSS selectors are more concise and readable with better performance, but limited to forward navigation and cannot select by text content. XPath is more powerful and flexible, can navigate in all directions, select by text content, and supports complex expressions, but has more verbose syntax. For a detailed comparison table and when to use each, see the [CSS Selectors vs XPath section](#css-selectors-vs-xpath-which-to-use-for-web-scraping) above.







Why isn't my CSS selector working even though the element exists in the HTML?Common reasons include: dynamic content loading via JavaScript, case sensitivity in attribute selectors, whitespace issues in class names, unexpected element structure, special characters needing escaping, or browser differences. [Use browser developer tools to test selectors](https://scrapfly.io/blog/answers/browser-developer-tools-in-web-scraping) and consider [XPath alternatives](https://scrapfly.io/blog/posts/parsing-html-with-xpath).







Can CSS selectors select elements based on their text content?No, standard CSS selectors cannot select elements based on text content. [Use XPath with text() function](https://scrapfly.io/blog/posts/parsing-html-with-xpath), JavaScript filtering, or non-standard extensions like `:contains()` in jQuery/Sizzle libraries.







How do I select a parent element with CSS selectors?Standard CSS selectors cannot select parent or ancestor elements. [Use XPath](https://scrapfly.io/blog/posts/parsing-html-with-xpath) (`//child[@class='target']/..`), JavaScript DOM traversal, or restructure your scraping logic to start from the parent element.







Which CSS selector is fastest for web scraping: class, ID, or attribute?ID selectors (`#id`) are fastest, followed by class selectors (`.class`), then attribute selectors (`[attr=value]`), element selectors (`div`, `span`), and complex selectors. Use IDs when available, combine element and class selectors, and avoid overly complex selectors for better performance.







How do I find CSS selectors for web scraping?Use your browser's Developer Tools (F12) to inspect elements: right-click the target element, select "Inspect", then right-click the HTML and choose "Copy → Copy selector". Test selectors using Ctrl+F in the Elements panel. For a complete walkthrough, see our [Finding CSS Selectors with Browser Developer Tools](#finding-css-selectors-with-browser-developer-tools) section above.







Can I use CSS selectors with web scraping APIs like Scrapfly?Yes, CSS selectors work seamlessly with [Scrapfly's web scraping API](https://scrapfly.io/web-scraping-api) and its [Python SDK](https://scrapfly.io/docs/sdk/python). Scrapfly handles page retrieval, JavaScript rendering, and [anti-bot bypass](https://scrapfly.io/docs/scrape-api/anti-scraping-protection), returning clean HTML that you can parse with CSS selectors using libraries like [parsel or BeautifulSoup](https://scrapfly.io/blog/posts/parsing-html-with-css).









 

    Table of Contents- [Key Takeaways](#key-takeaways)
- [CSS Selectors for Web Scraping](#css-selectors-for-web-scraping)
- [CSS Selectors in the Web Scraping Workflow](#css-selectors-in-the-web-scraping-workflow)
- [Finding CSS Selectors with Browser Developer Tools](#finding-css-selectors-with-browser-developer-tools)
- [Inspecting Elements to Find Selectors](#inspecting-elements-to-find-selectors)
- [Testing Selectors in the Browser](#testing-selectors-in-the-browser)
- [Tips for Creating Robust Selectors](#tips-for-creating-robust-selectors)
- [Real Example: Finding Product Prices](#real-example-finding-product-prices)
- [Cheatsheet](#cheatsheet)
- [Direct Child](#direct-child)
- [Any Descendant](#any-descendant)
- [Any Following Sibling](#any-following-sibling)
- [Direct Following Sibling](#direct-following-sibling)
- [Joining Selectors](#joining-selectors)
- [by Class](#by-class)
- [by ID](#by-id)
- [by Attribute](#by-attribute)
- [by Attribute Value](#by-attribute-value)
- [by Case Insensitive Attribute Value](#by-case-insensitive-attribute-value)
- [by Partial Attribute Value](#by-partial-attribute-value)
- [by Attribute Value Ignoring Minus Suffix](#by-attribute-value-ignoring-minus-suffix)
- [by Attribute Value Starting With](#by-attribute-value-starting-with)
- [by Attribute Value Ending With](#by-attribute-value-ending-with)
- [by Attribute Containing Word](#by-attribute-containing-word)
- [Reversing Matchers Using Not](#reversing-matchers-using-not)
- [First Child](#first-child)
- [Last Child](#last-child)
- [Nth Child](#nth-child)
- [Nth Last Child](#nth-last-child)
- [First Of Type](#first-of-type)
- [Last Of Type](#last-of-type)
- [Nth Of Type](#nth-of-type)
- [Only of Type](#only-of-type)
- [Has Descendant](#has-descendant)
- [Is Matcher](#is-matcher)
- [Getting Attribute Value](#getting-attribute-value)
- [Getting Element Text](#getting-element-text)
- [CSS Selectors vs XPath: Which to Use for Web Scraping?](#css-selectors-vs-xpath-which-to-use-for-web-scraping)
- [When to Use CSS Selectors](#when-to-use-css-selectors)
- [When to Use XPath](#when-to-use-xpath)
- [Practical Example](#practical-example)
- [FAQ](#faq)
 
    Join the Newsletter  Get monthly web scraping insights 

 

  



Scale Your Web Scraping

Anti-bot bypass, browser rendering, and rotating proxies, all in one API. Start with 1,000 free credits.

  No credit card required  1,000 free API credits  Anti-bot bypass included 

 [Start Free](https://scrapfly.io/register) [View Docs](https://scrapfly.io/docs/onboarding) 

 Not ready? Get our newsletter instead. 

 

## Explore this Article with AI

 [ ChatGPT ](https://chat.openai.com/?q=Summarize%20this%20page%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fcss-selector-cheatsheet) [ Gemini ](https://www.google.com/search?udm=50&aep=11&q=Summarize%20this%20page%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fcss-selector-cheatsheet) [ Grok ](https://x.com/i/grok?text=Summarize%20this%20page%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fcss-selector-cheatsheet) [ Perplexity ](https://www.perplexity.ai/search/new?q=Summarize%20this%20page%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fcss-selector-cheatsheet) [ Claude ](https://claude.ai/new?q=Summarize%20this%20page%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fcss-selector-cheatsheet) 



 ## Related Articles

 [  

 data-parsing xpath 

### Ultimate XPath Cheatsheet for HTML Parsing in Web Scraping

Ultimate companion for HTML parsing using XPath selectors. This cheatsheet contains all syntax explanations with interac...

 

 ](https://scrapfly.io/blog/posts/xpath-cheatsheet) [  

 data-parsing css-selectors 

### Parsing HTML with CSS Selectors

Introduction to using CSS selectors to parse web-scraped content. Best practices, available tools and common challenges ...

 

 ](https://scrapfly.io/blog/posts/parsing-html-with-css) [  

 python data-parsing 

### Ultimate Guide to JSON Parsing in Python

Learn JSON parsing in Python with this ultimate guide. Explore basic and advanced techniques using json, and tools like ...

 

 ](https://scrapfly.io/blog/posts/how-to-use-python-to-parse-json) 

  ## Related Questions

- [ Q How to select elements by attribute using CSS selectors? ](https://scrapfly.io/blog/answers/how-to-select-elements-by-attribute-containing-value-css-selectors)
- [ Q How to select elements by ID using CSS selectors? ](https://scrapfly.io/blog/answers/how-to-select-elements-by-id-css-selectors)
- [ Q How to select HTML elements by text using CSS Selectors? ](https://scrapfly.io/blog/answers/how-to-select-elements-by-text-using-css-selectors)
- [ Q How to select elements by class using CSS selectors? ](https://scrapfly.io/blog/answers/how-to-select-elements-by-class-css-selectors)
 
  



   



 Extract structured data with AI, **1,000 free credits** [Start Free](https://scrapfly.io/register)