The Useful HTML Parsing Library Parsel in Python

Parsel is a lightweight and efficient web data extraction library in the Python ecosystem, developed based on lxml (a high-performance XML/HTML parser). It supports CSS selectors, XPath expressions, and regular expressions, making it flexible for various web data extraction scenarios (either used independently or in conjunction with the Scrapy framework).

Advantages

  1. 1. Multi-selector support: Compatible with CSS, XPath, and regular expressions, allowing you to choose the most convenient extraction method as needed;
  2. 2. High performance: Based on lxml, the parsing speed far exceeds that of BeautifulSoup;
  3. 3. Lightweight and flexible: Minimal dependencies, can be used independently (no need for the Scrapy framework);

Installation

pip install parsel

Example

The core of Parsel is the <span>Selector</span> class — it encapsulates the parsed HTML/XML document and provides methods for data extraction using CSS, XPath, etc.

1. Initializing Selector

from parsel import Selector

# Example HTML text
html = """
<div class="movie-list">
    <div class="movie" id="movie1">
        <h3 class="title">The Wandering Earth 2</h3>
        <p class="score">9.2</p>
        <a href="/movie/296767" class="link">View Details</a>
    </div>
    <div class="movie" id="movie2">
        <h3 class="title">Full River Red</h3>
        <p class="score">8.5</p>
        <a href="/movie/301284" class="link">View Details</a>
    </div>
</div>
"""

# Create Selector object
# Method 1: Initialize from text
selector = Selector(text=html)

# Method 2: Read from requests response
import requests
response = requests.get("https://example.com/movies")
selector = Selector(text=response.content.decode("utf-8"))
selector = Selector(text=response.text)

Data Extraction Methods

<span>Selector</span> provides three core extraction methods, all returning results as <span>SelectorList</span>

1. Extraction Functions

Whether using CSS or XPath, you ultimately need to use the following functions to obtain specific data:

Method Function Return Type Example
<span>get()</span> Get the first matching result, returns <span>None</span> if no match String / None <span>selector.css(".title::text").get()</span>
<span>getall()</span> Get all matching results List (String) <span>selector.css(".title::text").getall()</span>
<span>extract()</span> Same as <span>getall()</span> (deprecated method, use <span>getall()</span> instead) List (String) <span>selector.xpath("//h3/text()").extract()</span>
<span>extract_first()</span> Same as <span>get()</span> (deprecated method, use <span>get()</span> instead) String / None <span>selector.xpath("//h3/text()").extract_first()</span>

2. CSS Selectors

The CSS selector syntax is consistent with front-end development, suitable for extracting elements with known class names or IDs.

Common syntax examples

Requirement CSS Syntax Example Code Result (based on previous HTML)
Select text with class <span>title</span> <span>.title::text</span> <span>selector.css(".movie .title::text").getall()</span> <span>["The Wandering Earth 2", "Full River Red"]</span>
Select element with ID <span>movie1</span> <span>#movie1</span> <span>selector.css("#movie1 .score::text").get()</span> <span>"9.2"</span>
Select <span>a</span> tag’s <span>href</span> attribute <span>a.link::attr(href)</span> <span>selector.css(".movie a.link::attr(href)").getall()</span> <span>["/movie/296767", "/movie/301284"]</span>
Select the 2nd <span>movie</span> element <span>.movie:nth-child(2) .title::text</span> <span>selector.css(".movie:nth-child(2) .title::text").get()</span> <span>"Full River Red"</span>

Chained calls: first select the parent element, then select child elements within the parent

# 1. First select all .movie parent elements
movie_selectors = selector.css(".movie")

# 2. Iterate over parent elements to extract each movie's information (chained calls)
for movie in movie_selectors:
    title = movie.css(".title::text").get()  # Only search within the current .movie
    score = movie.css(".score::text").get()
    link = movie.css("a.link::attr(href)").get()
    print(f"Movie: {title}, Score: {score}, Link: {link}")

3. XPath Selectors

XPath supports more complex node location (such as by text content, hierarchical relationships), suitable for scenarios where CSS is difficult to implement.

Common syntax examples

Requirement XPath Syntax Example Code Result (based on previous HTML)
Select all <span>h3</span> text <span>//h3/text()</span> <span>selector.xpath("//h3/text()").getall()</span> <span>["The Wandering Earth 2", "Full River Red"]</span>
Select text with class <span>score</span> <span>//p[@class="score"]/text()</span> <span>selector.xpath("//p[@class='score']/text()").getall()</span> <span>["9.2", "8.5"]</span>
Select <span>a</span> tag’s <span>href</span> attribute <span>//a/@href</span> <span>selector.xpath("//a/@href").getall()</span> <span>["/movie/296767", "/movie/301284"]</span>
Select movie titles with score > 9 <span>//div[./p[@class="score"]/text() > 9]/h3/text()</span> <span>selector.xpath("//div[./p[@class='score']/text() > 9]/h3/text()").get()</span> <span>"The Wandering Earth 2"</span>

Relative XPath

When traversing parent elements, XPath needs to start with <span>.</span> to indicate “current node”; otherwise, it will match globally:

movie_selectors = selector.xpath("//div[@class='movie']")
for movie in movie_selectors:
    # Use .// to indicate "search within the current movie node"
    title = movie.xpath(".//h3/text()").get()
    score = movie.xpath(".//p[@class='score']/text()").get()
    print(f"{title}: {score}")

4. Method 3: Regular Expressions

When the text format is irregular (such as containing extra characters), use <span>re()</span> or <span>re_first()</span> combined with regular expressions for extraction.

# If the HTML contains score as <p class="score">Score: 9.2</p>
score_text = selector.css(".score::text").get()  # "Score: 9.2"
# Use regex to extract the numeric part
score = selector.css(".score::text").re_first(r"Score:(\d+\.\d+)")  # "9.2"

# Link format: /movie/296767 → extract 296767
links = selector.css("a.link::attr(href)").getall()  # ["/movie/296767", "/movie/301284"]
# Use re() to extract numbers from each link
movie_ids = selector.css("a.link::attr(href)").re(r"/movie/(\d+)")  # ["296767", "301284"]

Example: Playwright + Parsel Handling Dynamic Web Pages

from parsel import Selector
from playwright.sync_api import sync_playwright

# Use Playwright to render dynamic web pages
with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)  # Headless mode
    page = browser.new_page()
    page.goto("https://example.com/dynamic-movies")  # Dynamic web page
    page.wait_for_selector(".movie")  # Wait for target element to load
    html = page.content()  # Get rendered HTML
    browser.close()

# Use Parsel to extract data
selector = Selector(text=html)
titles = selector.css(".movie .title::text").getall()
print(titles)

Parsel is a great helper for parsing HTML

Leave a Comment