Skip to content

Compare

BeautifulSoup vs lxml vs selectolax: measured parsing speed

A reproducible local benchmark of BeautifulSoup (html.parser and lxml), lxml, and selectolax on a 125 KB fixture, plus API, XPath, and malformed-HTML trade-offs.

Last updated 3 min readBy CrawlerBros Editorial

Tested with Python 3.14.2, BeautifulSoup 4.14.3, lxml 6.0.2, selectolax 0.4.10 on 2 November 2026. Library versions and dates are part of the evidence, not decoration.

BeautifulSoup is a forgiving Python parsing library with a friendly tree API. lxml is a fast C-backed parser with full XPath. selectolax is a fast C-backed parser with a smaller CSS-first API. The speed difference is real and large; the ergonomics difference is also real. This page publishes our measurement rather than repeating a benchmark from elsewhere.

The benchmark

We generated a 125,598-byte HTML fixture with 1,000 product cards, parsed it, and extracted the 1,000 headings. We ran three warm-up iterations and reported the median of 15 timed runs. The machine was a Windows 11 PC with Python 3.14.2, BeautifulSoup 4.14.3, lxml 6.0.2, and selectolax 0.4.10. The script is published with this site as scripts/relaunch/benchmarks/parse-benchmark.py.

Parser Median time (ms) Pages/sec (1,000-card fixture)
BeautifulSoup + html.parser 133.75 7.5
BeautifulSoup + lxml 102.75 9.7
lxml (XPath) 11.32 88.3
selectolax (CSS) 3.88 257.6

These numbers measure parsing and one selector extraction. They do not include network time, retries, storage, or browser rendering. A real crawl is usually dominated by network and politeness delays, so a 30× parser difference does not mean a 30× faster crawl. It means the parser stops being the bottleneck when you need to process saved HTML at volume.

What the numbers mean

  • BeautifulSoup is the slowest because it builds a rich Python object tree. html.parser is pure Python; using lxml as the BeautifulSoup backend is faster but still pays for the BeautifulSoup wrapper.
  • lxml is much faster and gives you XPath. It is stricter about malformed HTML than BeautifulSoup, though lxml.html is still forgiving.
  • selectolax is the fastest in this fixture, with a CSS-first API and a smaller surface. It is a good choice for high-volume extraction where the selectors are simple.

The benchmark is a microbenchmark. Different HTML, deeper trees, and more complex selectors change the ratios. Run it on your own corpus before making a decision.

API and ergonomics

BeautifulSoup wins on forgiveness and discoverability. soup.find, select, get_text, and the navigation API are easy to learn, and a malformed page rarely raises. It is the best choice for exploratory scraping, one-off scripts, and pages with messy markup.

lxml gives you xpath(), fast parsing, and a mature XML/HTML toolkit. The API is less friendly, and namespace handling can surprise you. It is the best choice when you need XPath or when parsing is the bottleneck.

selectolax has a small API: parse, css(), .text(), attributes. It is fast and pleasant for simple extraction. It is not the library to choose if you need intricate tree manipulation or the broadest malformed-HTML tolerance.

Feature comparison

Feature BeautifulSoup lxml selectolax
CSS selectors Yes Yes (via cssselect) Yes
XPath No (not natively) Yes No
Malformed HTML Very forgiving Forgiving Forgiving
Pure Python html.parser backend No No (C/Cython)
Speed Slow Fast Fastest
Tree editing Yes Yes Limited
Learning curve Low Medium Low

A practical recommendation

  • Start with BeautifulSoup + html.parser for a new scraper. It is the easiest to debug and the parser is rarely the bottleneck on a polite crawl.
  • Move to lxml when you need XPath or when you are parsing saved HTML at volume.
  • Use selectolax for a high-throughput extraction service where the selectors are simple and the input is well-formed enough.
  • Do not choose a parser because of a benchmark alone. Measure on your corpus, with your selectors.

The HTML and DOM lesson covers the tree model, and the CSS/XPath lesson covers the query languages.

Reproduce it

python -m pip install beautifulsoup4 lxml selectolax
python scripts/relaunch/benchmarks/parse-benchmark.py

The script prints the fixture size and the median/pages-per-second for each parser. Change CARDS, RUNS, and the selector to match your workload.

Sources

Sources checked