selectolax im Test: Ein schneller HTML-Parser, der BeautifulSoup hinter sich lässt und mit lxml gleichzieht

Zuletzt aktualisiert am July 17, 2026
selectolax im Test: Ein schneller HTML-Parser, der BeautifulSoup hinter sich lässt und mit lxml gleichzieht
KI-Zusammenfassung
This selectolax review measures the parser against lxml, BeautifulSoup, parsel, and different backend choices across page sizes, selector coverage, memory use, and edge-case HTML behavior. It confirms that selectolax is far faster than BeautifulSoup and competitive with lxml on full parse-and-query tasks, while also showing that lxml can be faster on pure parsing in this test environment. The article explains the Lexbor and Modest engines, CSS selector gaps, the template-content issue, memory savings, licensing details, and when selectolax is a strong replacement for slower Python parsing workflows.

Jeder Beitrag über den „schnellsten Python-HTML-Parser“ nennt irgendwann selectolax, und fast immer endet die Geschichte bei „deutlich schneller als BeautifulSoup“. Das stimmt auch. Was dabei meist fehlt: Was passiert, wenn man selectolax direkt mit lxml vergleicht? Denn dort bekommt „schnellster“ eben ein Sternchen.

Also habe ich es sauber gebenchmarkt: selectolax (mit beiden Backends) gegen lxml, BeautifulSoup mit html.parser und mit lxml sowie parsel, und zwar über fünf Seitengrößen von 1 KB bis 10 MB. Jeder Messwert ist der Median aus drei getrennten Prozessläufen. selectolax schlug BeautifulSoup sehr deutlich und zog mit reinem lxml gleich — verlor aber beim reinen Parsen gegen lxml. Alle Zahlen unten sind vorläufig und stammen von einem einzigen Rechner (macOS arm64, Python 3.14.2); die Skripte sind im Repository, also teste sie auf deinem System, bevor du mich zitierst.

Was selectolax eigentlich ist – und was nicht

selectolax ist ein Python-Binding für zwei C-Engines — Modest und Lexbor — die HTML5 parsen und per CSS-Selektoren abfragen. Es ist kein Crawler, kein Browser und kein „Scraper“ im Sinne von „Button klicken und los“. Es ist das Werkzeug, dem du einen HTML-Block gibst, nachdem du ihn bereits abgerufen hast. Der eigene Kurzsatz des Maintainers lautet: „A fast HTML5 parser with CSS selectors, written in Cython, using Modest and Lexbor engines.“

Es gibt zwei Backends, und der Unterschied ist wichtiger, als die Doku vermuten lässt:

  • LexborHTMLParser (Lexbor-Engine) — laut README die empfohlene Wahl ab 2024.
  • HTMLParser (Modest-Engine) — das ursprüngliche Backend, dessen zugrunde liegende C-Bibliothek laut derselben README „nicht mehr gepflegt wird“.

Ein paar Fakten vorab, bevor es um Geschwindigkeit geht: Zum Repo-Snapshot vom 2026-07-10 hatte selectolax 1.653 Sterne, die neueste Version war v0.4.10 (Mai 2026), und PyPI nennt Python >=3.9,<3.15. Die Installation ist der unspektakulärste Teil des ganzen Tests: pip install selectolax zog direkt ein 2,3 MB großes vorgefertigtes cp314-Wheel und lief sofort auf Python 3.14 — kein Browser-Download, kein doctor-Schritt, kein Kompilieren. Das ist der leise Vorteil eines reinen Parsers gegenüber browsergestützten Tools: importieren und loslegen.

Ein Lizenzpunkt, den man nicht unter den Tisch fallen lassen sollte: Das Python-Binding steht unter MIT, aber das Wheel bringt die kompilierte Engine mit, und dafür gelten eigene Lizenzen — Modest ist LGPL-2.1, Lexbor ist Apache-2.0. „selectolax ist MIT“ stimmt also für den Python-Code, ist aber für das tatsächlich ausgelieferte Binärpaket unvollständig. Wenn dein Legal-Team auf weiterverteilte Komponenten achtet, ist genau das der relevante Hinweis.

Die Geschwindigkeitsfrage – mit echten Zahlen beantwortet

Getestet habe ich folgende Aufgabe: den HTML-String parsen, jedes <h3 class="title">-Element auslesen und alle <a>-hrefs extrahieren. Die Latenz in Millisekunden ist jeweils der Median aus drei getrennten Prozessläufen; die Streuung zwischen den Läufen blieb bei den C-gestützten Parsern über die meisten Größen hinweg unter etwa 5 %. Bevor eine Zelle gemessen wurde, habe ich die Ausgabe jedes Parsers auf einen Content-Hash reduziert, damit Parser, die stillschweigend weniger Arbeit leisten, auffallen und ausgeschlossen werden würden — auf diesen Seiten lieferten alle sechs Varianten bei jeder Größe identische Ergebnisse, also ist der Vergleich tatsächlich sauber. Die vollständigen Daten liegen in bench_parse.json.

selectolax ist bei allen Seitengrößen 12-17x schneller als BeautifulSoup

Seiteselectolax (Lexbor)selectolax (Modest)lxmlparselBS (lxml)BS (html.parser)
1 KB0.0270.0290.0360.0440.2810.323
10 KB0.1600.1710.1660.2281.7052.049
100 KB1.4641.5651.4232.02016.520.6
1 MB14.90116.914.17720.9181.9232.6
10 MB159.9247.9172.9231.92261.62788.7

Gegenüber BeautifulSoup: etwa 12–17x, und die gängige Erzählung unterschätzt es

Setzt man die Werte ins Verhältnis, ist selectolax-Lexbor auf einer 1-KB-Seite rund 12x schneller als BeautifulSoup(html.parser) und bei 10 MB rund 17x schneller, und etwa 10–14x schneller als BeautifulSoup(lxml) über denselben Bereich. Die oft zitierte Zahl — „selectolax ist etwa 4–5x schneller als BeautifulSoup“ — ist gegenüber html.parser zu niedrig und nur gegenüber der lxml-gestützten BeautifulSoup ungefähr richtig. Der reale Faktor hängt davon ab, welche BeautifulSoup-Variante du meinst und wie viel du pro Seite extrahierst.

Das passt auch zu den Zahlen aus der README, die auf einen 25,5x-Vorsprung gegenüber BeautifulSoup(html.parser) hindeuten. Keines der beiden Ergebnisse ist falsch. Die README-Aufgabe (Titel, Links, Skripte und Meta-Daten von kleinen Homepages) extrahiert weniger pro Seite, wodurch der Overhead von BeautifulSoup stärker ins Gewicht fällt. Für realistische Parse-und-Extrahier-Workloads gilt daher grob: selectolax ist etwa 10–15x schneller als BeautifulSoup, bei kleinen Seiten und wenig Extraktion sogar noch mehr.

Wenn dein Engpass gerade ein Berg von BeautifulSoup-Code ist, der Seiten durcharbeitet, ist das eine Migration, die sich sofort auszahlt. Dieser Fall ist unstrittig. Der nächste ist es nicht.

Gegenüber lxml: ein Gleichstand – und lxml gewinnt den Teil, den viele gar nicht separat messen

Schau dir die Zeilen 100 KB und 1 MB an. Lexbor und lxml liegen innerhalb von rund 5 % beieinander, die Laufzeitspannen überlappen sich, und nach meiner Methodik ist das ein Gleichstand — kein Sieger, kein „schneller“. Der einzige Punkt, an dem selectolax wirklich vorne liegt, ist die 10-MB-Seite (159,9 ms gegenüber 172,9 ms, also 8,1 % Unterschied mit nicht überlappenden Intervallen). Im Gesamttest zieht selectolax also mit lxml gleich und liegt nur bei den allergrößten Dokumenten vorn.

selectolax zieht im Gesamttest mit lxml gleich, aber lxml ist beim reinen Parsen 33-34 Prozent schneller

Dann habe ich den Baumaufbau von der CSS-Abfrage getrennt, und das Ergebnis dreht sich auf eine Weise, die viele Berichte übersehen. Beim reinen Parsen ohne Abfrage war lxml auf diesem Rechner durchgehend rund 33–34 % schneller als selectolax-Lexbor — 77,9 ms gegenüber 116,6 ms auf der 10-MB-Seite. Beim Gesamttest gleichen sich beide ohnehin an, und meine Arbeitshypothese ist (ohne dass ich sie mit einem Attributionsexperiment bewiesen hätte), dass auf diesen Seiten die CSS-Abfrage nur einen kleinen Teil der Gesamtzeit ausmacht, sodass lxmls Vorteil beim Parse-Schritt am Ende verwässert wird.

Das ist die angreifbarste Aussage in diesem ganzen Test, und ich möchte offen sagen, warum. Sie widerspricht der gängigen Meinung, und der einzige veröffentlichte Benchmark, den ich gefunden habe und der nur das Parsen isoliert — aows.jpt.sh — berichtet das Gegenteil und sieht selectolax etwa 4x schneller. Deshalb habe ich das Ergebnis abgesichert: Es stammt von einer einzigen Plattform (macOS arm64, Python 3.14, vorgefertigte cp314-Wheels — Linux x86_64 oder ein Source-Build wurden nicht getestet), wurde über vier Seitengrößen gegengeprüft und hielt sich überall, und ich habe es mit zwei unterschiedlichen lxml-APIs erneut geprüft, um einen API-Effekt auszuschließen. Beide lxml-APIs waren bei jeder Größe schneller als selectolax-Lexbor. Ich stelle nicht als gesicherte Wahrheit hin, dass „lxml schneller parst“ — ich zeige nur, was mein Benchmark auf dieser Maschine ergeben hat, inklusive Skript. Bitte auf deinem System nachmessen.

Noch eine Teilmessung: Beim Abfragen von 100.000 <a>-Elementen auf einer flachen Seite lagen lxml und selectolax-Modest gleichauf (33,30 ms gegenüber 34,19 ms, Intervalle überlappen), während selectolax-Lexbor beiden um etwa 15 % hinterherhinkt. Gemein haben alle drei C-Engines, dass sie 5–7x schneller sind als parsel oder BeautifulSoup bei Massen-Selektion, weil deren Python-Objekt-pro-Node-Modell der eigentliche Bremsklotz ist. Die Aussage „selectolax ist der schnellste bei CSS-Massenabfragen“ stimmt also ebenfalls nicht — Modest zieht nur mit lxml gleich, Lexbor verliert gegen es.

Die ehrlichste Zusammenfassung: selectolaxs Vorsprung gegenüber lxml ist kein breiter Full-Task-Speedvorteil. Es gewinnt nur auf der größten Seite. Seine Stärke liegt woanders — API-Ergonomie, Verhalten bei kaputtem Input und moderne CSS-Unterstützung. Darum geht es im restlichen Test.

Speicher und Kaltstart: nach RSS beurteilen, nicht nach deinem Profiler

Beim Speicher muss ich meine früheren Zahlen korrigieren, und genau das ist der Punkt. Gemessen als RSS-Differenz auf der 10-MB-Seite bei deaktiviertem tracemalloc nutzt BeautifulSoup etwa 1,5–1,8x so viel Speicher wie selectolax oder lxml — von 1,51x (BS-lxml mit 218,4 MB gegenüber Lexbor mit 144,6 MB) bis 1,75x am oberen Ende. selectolax und lxml liegen in derselben schlanken Kategorie; lxml ist nach RSS der sparsamste Parser.

selectolax-Speicherklasse nach RSS gemessen, ohne Profiler

Ein früherer Durchlauf von mir sprach von „~3x“, und das war aus einem lehrreichen Grund falsch: gemessen wurde mit laufendem tracemalloc, und dessen Buchhaltung pro Allokation verdoppelt die scheinbar belegte RSS des Parsers mit den meisten Allokationen ungefähr. Deshalb der Hinweis für alle, die Parser-Speicher benchmarken: nach RSS messen, mit ausgeschaltetem Profiler. Mit tracemalloc nach Spitzenwerten sortiert man C-gestützte Parser speziell falsch ein — so wirkte selectolax-Lexbor schwerer als Modest, obwohl sie nach echter RSS ziemlich dicht beieinander liegen. BeautifulSoup ist hier tatsächlich der schwerste Kandidat; nur nicht mit dem 3x-Abstand, den ein verfälschtes Messinstrument suggerierte.

Der Kaltstart ist klein, aber messbar: selectolax importiert in etwa 14 ms, also ungefähr auf Augenhöhe mit lxml und rund 2,3x schneller als bs4 oder parsel. Wenn du ein CLI-Tool oder eine serverless Funktion auslieferst, bei der die Importzeit bei jedem Aufruf zählt, ist dieser Abstand durchaus relevant.

CSS-Selector-Abdeckung: stark, aber mit ein paar echten Lücken

Die CSS-Abdeckung wurde mit einer Matrix aus 41 Fällen geprüft. Jeder Selector wurde gegen ein Fixture mit eindeutig korrektem Ergebnis getestet, dazu kam ein absichtlich fehlerorientierter Durchlauf, der die Lexbor-Engine zu Fall bringen sollte. Jeder Fall lief in einem eigenen Subprozess, was sich als notwendig herausstellte — einer von ihnen bringt sonst den gesamten Interpreter zum Absturz. Das Ergebnis:

Vergleich der CSS-Selector-Abdeckung: soupsieve 41/41, Lexbor 39/41

EnginePASSFALSCHNICHT UNTERSTÜTZTPROCESS_ABORT
soupsieve41000
selectolax Lexbor39020
lxml (cssselect)37130
parsel (cssselect)37130
selectolax Modest35321

Wenn man die „feindlichen“ Selektoren mit einbezieht, ist Lexbor nicht der eindeutige Sieger — soupsieve ist es, mit glatten 41/41 gegenüber Lexbors 39/41. Die beiden Ausfälle von Lexbor sind :lang(en) und :dir(rtl), die es mit Parse-Fehler ablehnt. Bei allem anderen ist die Engine korrekt, inklusive :has(), :is(), :where() und case-insensitiven Attributen.

Worin Lexbor wirklich glänzt, ist der Vergleich mit dem cssselect-Stack. Der Vorzeige-Selector aus der README — div > :nth-child(2n+1):not(:has(a)) — liefert sowohl auf beiden selectolax-Engines als auch auf soupsieve die richtigen Elemente, aber auf lxml und parsel das falsche Ergebnis, ohne Fehlermeldung. Ein Scraper, der diesen Selector in Scrapy oder parsel übernimmt, bekommt stillschweigend falsche Daten. Zur Einordnung: cssselect unterstützt :has() seit Version 1.2.0 (2022), und ich habe 1.4.0 getestet; das ist also „unterstützt, aber bei der Kombination falsch ausgewertet“ und nicht „nicht unterstützt“. Dieses stille Fehlverhalten bei genau dieser Kombination ist auch nicht im cssselect-Issue-Tracker dokumentiert, der die Grenzen von :has() eher als Fehler beschreibt. Lexbor verarbeitet außerdem das fallunabhängige Attribut-Flag [data-role="LEAD" i], das cssselect komplett ablehnt.

Es gibt aber zwei Lücken, die Migrationen entscheiden können. selectolax unterstützt gar kein XPath — keines der beiden Backends stellt xpath() bereit — und auch keine ::text- bzw. ::attr()-Pseudoelemente, weil das eine Erweiterung von parsel/Scrapy und kein echtes CSS ist. Wenn deine bestehenden Scraper stark auf XPath setzen, ist das die größte Hürde; dann würdest du Selektoren neu schreiben, nicht bloß eine Bibliothek austauschen. Auf der anderen Seite bringt Lexbor eine :lexbor-contains("text" i)-Pseudoklasse für fallunabhängige Textsuche mit, die weder lxml noch parsel noch Standard-CSS anbieten — und sie funktioniert wie dokumentiert.

Robustheit bei hässlichem HTML – hier verdient selectolax seinen Platz

Echte Scraping-Arbeit heißt, dem Parser Müll vorzuwerfen und zu hoffen, dass er nicht umkippt. Ich habe 18 adversariale Inputs getestet, und genau in dieser Kategorie spricht am meisten für selectolax gegenüber lxml.

Gib lxml.html.fromstring einen leeren String oder nur Leerzeichen, und es wirft ParserError("Document is empty"). Beide selectolax-Engines liefern stattdessen sauber einen leeren, gültigen Baum. Für Scraper, die über eine URL-Liste laufen und bei denen einzelne Antworten leer zurückkommen, ist das ein Fehler weniger, den man mit try/except absichern muss. selectolax verarbeitete außerdem 100.000 Elemente ohne Stack Overflow.

Die deutlichste Trennung zeigte sich bei tiefer Verschachtelung. Bei 1.000 und 5.000 Ebenen verschachtelter <div>-Elemente wirft lxml den tiefsten Inhalt stillschweigend weg, während selectolax ihn behält. libxml2 begrenzt die Parse-Tiefe auf etwa 256 Ebenen und schneidet den Baum ohne Fehlermeldung ab, sodass der tiefste Text schlicht nicht mehr erreichbar ist. Beide selectolax-Engines liefern den vollständigen Baum zurück. Das ist das Spiegelbild der <template>-Falle, auf die ich gleich komme: Dort verwirft Lexbor Inhalt, den die anderen behalten; hier verwirft lxml Inhalt, den selectolax behält.

Nicht jedes Feld war ein Sieg. Das Modest-Backend beendet den gesamten Python-Interpreter mit einem SIGABRT, wenn es auf :dir() trifft — keine auffangbare Exception, sondern ein harter Prozessabbruch. Das ist ein echtes Robustheitsproblem für alle, die noch auf dem alten Backend laufen, und genau die Art von Fehler, die man erst sieht, wenn sie um 3 Uhr morgens einen Produktionsjob abschießt.

Zwei stille Datenverlustfallen, die du vor dem Einsatz kennen solltest

Beides ist upstream dokumentiert, also keine Entdeckung von mir — aber beides kostet real Daten, still und ohne großen Warnhinweis in der README.

Lexbor übersieht <a>-Elemente innerhalb von <template>

Auf der live getesteten MDN-Seite fand selectolax-Lexbor 497 Links, während lxml, beide BeautifulSoup-Backends und sogar selectolaxs eigenes Modest-Backend 508 fanden. Die fehlenden elf waren ein Sprachumschalter und ein Discussions-Link innerhalb von <template>-Elementen (die Seite nutzt Lit-Webkomponenten).

selectolax Lexbor Template-Falle: 497 Links statt 508 Links

Die Ursache ist grundsätzlich legitim: Laut HTML5-Spezifikation wird Inhalt in <template> in ein eigenes, inertes Fragment geparst und nicht in den normalen DOM; Lexbor folgt dem strikt — tree.css("a") steigt nicht in Template-Inhalt hinab. lxml, beide BeautifulSoup-Backends und Modest flatten diesen Inhalt in den Hauptbaum, weshalb sie die Links finden. Das ist ein dokumentiertes offenes Problem (selectolax#146, mit der Engine-Ursache bei lexbor#170), und beide Sichtweisen sind vertretbar — Lexbors Verhalten ist sogar arguably näher an der Spezifikation. Aber ein Entwickler auf dem empfohlenen Backend verpasst diese Daten stillschweigend, ohne Fehler. Umgekehrt sollte man auch sagen: Die anderen Parser zeigen inertes Template-Material, das ein Browser nie rendert, und liefern dir damit Phantomdaten, die ein Nutzer gar nicht sehen kann. Der verlässliche Ausweg ist für genau diese Seite das Modest-Backend oder eine andere Bibliothek.

Nicht-UTF-8-Bytes beschädigen .text() stillschweigend

Wenn du selectolax Bytes gibst, die kein gültiges UTF-8 sind, gelingt das Parsen zunächst — die Beschädigung zeigt sich erst später, und das ist schlimmer als ein sauberer Absturz. Bei "<p>café éè</p>".encode("latin-1") gibt Lexbors .text() Ersatzzeichen zurück, Modests .text() schneidet die problematischen Bytes stillschweigend ab, und beide Engines werfen erst bei .html einen UnicodeDecodeError. Das Binding dekodiert beim Zurücklesen strikt als UTF-8, nicht bereits beim Parsen. Das hängt mit einem bekannten selectolax-Issue zur Striktheit beim Encode/Decode zusammen.

Die Lösung ist nur eine Zeile und sollte zur Routine gehören: dekodiere die Bytes vorher selbst — LexborHTMLParser(resp.content.decode("latin-1")) — dann geben beide Engines korrekt 'café éè' zurück. In der Praxis solltest du selectolax immer einen str übergeben, nie rohe nicht-UTF-8-bytes. Das steht in der README nicht ausdrücklich.

Produktionsaspekte, die nur als Einzelmessung vorliegen

Die nächsten Ergebnisse habe ich nur einmal gemessen, nicht dreifach gegengeprüft. Deshalb sind sie eher Signale als endgültige Zahlen.

Am interessantesten ist das Thread-Skalieren. Beim 48-maligen Parsen einer 1-MB-Seite über vier Threads zeigte selectolax einen Wall-Clock-Speedup von etwa 3,5–3,9x — das ist das typische Muster einer Bibliothek, die beim C-Parsen den GIL freigibt —, während BeautifulSoup(lxml) bei Threads deutlich langsamer wurde, also eher auf GIL-Serialisierung hindeutet. lxml lag dazwischen und war nicht eindeutig. Für die Free-Threading-Ära, in die Python gerade hineingeht, ist ein selectolax-Parsen, das sich über Threads parallelisiert, gegenüber BeautifulSoup ein echter, wenn auch vorläufiger Vorteil. Das ist allerdings nur ein Thread-Wert auf einer Seitengröße, und der Mechanismus bleibt eine Hypothese, weil ich nicht ins C-Profiling eingestiegen bin.

Zu Leaks: Über 2.000 Parse-Extraktions-Lösch-Zyklen bei 1 MB zeigte keiner der drei Parser den linearen RSS-Anstieg eines Memory-Leaks — jedes Verhalten stabilisierte sich in einem begrenzten Arbeitsspeicherbereich. Ich glaube diesem Resultat vor allem deshalb, weil ich zuvor einen bekannten Leak-Testfall mit demselben Instrument durchlaufen ließ und dieser wie vorgesehen auf +198 MB anstieg; damit war belegt, dass das Instrument einen Leak erkennen kann und ihn bei den Parsern einfach nicht fand. Und ein Node-Handle, das nach dem Verlassen seines Baums weiterlebte, blieb benutzbar, ohne Segfault. Alles Einzelbeobachtungen, nichts davon ein mehrstündiger Dauerlauf.

Wo selectolax hingehört – und wo es den Stab weiterreicht

Alles oben dreht sich um eine Aufgabe: HTML, das du bereits hast, schnell in strukturierte Daten umzuwandeln. Genau das kann selectolax sehr gut. Was es bewusst nicht tut: die Seite abrufen, JavaScript rendern, Proxys rotieren, CAPTCHAs lösen oder herausfinden, welche Elemente du überhaupt brauchst. Das bleibt alles dein Code. selectolax ist die Parse-Schicht und gibt nicht vor, mehr zu sein.

Genau hier liegt die Grenze zu einem verwalteten Extraktionsdienst, der über einem Parser sitzt statt ihn zu ersetzen. Wenn du die Fetch-Render-Anti-Bot-Extraktionskette lieber nicht selbst bauen und pflegen willst, stellt Thunderbit das als API, MCP-Server und CLI bereit — POST /distill verwandelt eine Seite in sauberes Markdown, und POST /extract liefert schema-matched strukturiertes JSON, während JavaScript-Rendering und Anti-Bot für dich übernommen werden. Das ist eine andere Schicht des Problems: selectolax nimmst du, wenn du das HTML bereits hast und rohe Parsing-Geschwindigkeit unter eigener Kontrolle willst; etwas wie Thunderbits API, MCP-Server oder CLI nimmst du, wenn Abruf und Extraktion bereits erledigt werden sollen und du nur strukturierte Daten zurückhaben willst. Kein Ersatz — sondern eine andere Flughöhe im selben Stack.

Thunderbit für Web-Datenextraktion testen

Vorteile, Nachteile und wer es wirklich nutzen sollte

Worin selectolax gewinnt:

  • Etwa 12–17x schneller als BeautifulSoup bei realistischen Parse-und-Extrahier-Workloads, stabil über drei Größenordnungen hinweg.
  • Schlanker Speicherverbrauch (lxml-Niveau, etwa 1,5–1,8x sparsamer als BeautifulSoup) und ein Import in rund 14 ms.
  • Robust bei Eingaben, an denen lxml scheitert — leer, nur Leerzeichen und extrem tiefe Verschachtelung.
  • Moderne CSS-Funktionen inklusive :has(), :is(), :where(), fallunabhängiger Attribute und des nur in Lexbor verfügbaren :lexbor-contains().
  • Ein None-sicheres DOM zum Lesen und Schreiben: fehlende Elemente liefern None oder [] statt Exceptions, und der Baum lässt sich tatsächlich verändern und wieder serialisieren.
  • Aktive Pflege (v0.4.10, Mitte 2026) und einfache Installation.

Worin es nicht gewinnt:

  • Nicht generell schneller als lxml — im Gesamttest unentschieden, beim reinen Parsen auf meinem Benchmark sogar langsamer.
  • Kein XPath und keine ::text/::attr()-Syntax — eine harte Migrationsgrenze für XPath-basierte Scraper.
  • Zwei stille Datenverlustfallen: <template>-Inhalte mit Lexbor und nicht-UTF-8-Bytes über .text().
  • Das Modest-Backend ist ein Legacy-Backend und kann bei :dir() mit SIGABRT abstürzen.
  • Alle Zahlen hier stammen nur von einer Plattform (macOS arm64, Python 3.14) und sind vorläufig.

Solltest du selectolax verwenden? Ja, wenn du Parsing-Geschwindigkeit auf lxml-Niveau mit einer freundlicheren, None-sicheren API und deutlich besserem Verhalten bei leerem oder fehlerhaftem Input willst — und bereit bist, im CSS-only-Bereich zu bleiben. Wenn deine Codebasis auf XPath baut, sind die Umstellungskosten real, und das solltest du ehrlich abwägen. Und wenn du „den einen schnellsten Parser“ suchst, dann ist die korrekte Antwort aus diesem Test: selectolax und lxml liegen so nah beieinander, dass die Entscheidung eher von Ergonomie und Robustheit abhängt als von roher Geschwindigkeit. Das ist ohnehin der bessere Grund, ein Tool auszuwählen.

Thunderbit für Web-Datenextraktion testen Get Started Free

FAQs

Ist selectolax schneller als BeautifulSoup? Ja, eindeutig — ungefähr 12–17x schneller als BeautifulSoup(html.parser) und 10–14x schneller als BeautifulSoup(lxml) bei einer realistischen Parse-und-Extrahier-Aufgabe, stabil von 1 KB bis 10 MB (macOS arm64, Python 3.14). Die oft genannte Zahl von „4–5x“ unterschätzt den Unterschied gegenüber html.parser deutlich.

Ist selectolax schneller als lxml? Nicht grundsätzlich. Beim vollständigen Parse-und-Extrahier-Task liegen beide bei 100 KB und 1 MB gleichauf, und selectolax gewinnt nur bei der 10-MB-Seite. Beim reinen Parsen ohne Abfrage war lxml auf meinem Rechner sogar etwa 33–34 % schneller — ein Ergebnis, das der gängigen Meinung widerspricht und deshalb als plattformgebunden gekennzeichnet ist. Bitte auf eigener Hardware prüfen.

Soll ich das Lexbor- oder das Modest-Backend verwenden? In fast allen Fällen Lexbor — das ist die gepflegte, funktionsreiche Engine, die die README empfiehlt und die bessere CSS-Abdeckung bietet. Die Ausnahme ist eine Seite, die Inhalte in <template>-Elementen versteckt, denn dort verhält sich Lexbor spezifikationskonform und übersieht diesen Inhalt, während Modest ihn zufällig mitnimmt. Modest hat außerdem scharfe Kanten, darunter einen harten Interpreter-Absturz bei :dir().

Unterstützt selectolax XPath? Nein. Keines der beiden Backends stellt eine xpath()-Methode bereit — selectolax arbeitet ausschließlich mit CSS. Wenn deine Scraper auf XPath angewiesen sind, bedeutet die Migration, dass du Selektoren neu schreiben musst; das ist die größte einzelne Hürde beim Wechsel von lxml- oder parsel-basierten Stacks zu selectolax.

Warum ist meine selectolax-Ausgabe fehlerhaft oder fehlen Elemente? Meistens gibt es zwei Ursachen. Wenn Text mit Ersatzzeichen oder fehlenden Umlauten zurückkommt, hast du wahrscheinlich rohe nicht-UTF-8-Bytes übergeben — dekodiere sie vor dem Parsen erst zu einem str (resp.content.decode("latin-1")). Wenn auf einer modernen Seite Links oder Elemente fehlen, liegen sie möglicherweise in <template>-Tags, in die das Lexbor-Backend nicht hineinläuft; verwende für genau diese Seite Modest oder einen anderen Parser.

Ke
Ke
CTO bei Thunderbit | Senior Data Scientist & ML-Experte Mit fast zehn Jahren Erfahrung in Machine Learning und Data Science ist Ke Shen Absolvent der Columbia University und ehemaliger Senior Data Scientist bei Walmart Labs. Mit tiefgreifender, von Fachkollegen anerkannter Expertise in Python, R, Java und Statistik teilt er praxiserprobte Einblicke dazu, wie sich komplexe KI-Algorithmen von der Theorie in eine produktionsreife Architektur überführen lassen.
Inhaltsverzeichnis
Thunderbit · KI-Webdaten-Agent

Daten von jeder Seite in 1 Klick extrahieren

Vertrauen von über 250.000 Nutzern
Kostenloser Plan verfügbar
Daten mit KI extrahieren
Daten einfach in Google Sheets, Airtable oder Notion übertragen
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week