Fiecare articol despre „cel mai rapid parser HTML în Python” ajunge, mai devreme sau mai târziu, la selectolax, și aproape toate se opresc la ideea că este „mult mai rapid decât BeautifulSoup”. Partea asta este adevărată. Ce lipsește de obicei este comparația cu lxml — pentru că acolo, eticheta de „cel mai rapid” capătă un asterisc.
Așa că l-am benchmarkat cum trebuie: selectolax (ambele backend-uri) împotriva lxml, BeautifulSoup pe html.parser și pe lxml, plus parsel, pe cinci dimensiuni de pagină, de la 1 KB la 10 MB, cu fiecare măsurătoare raportată ca mediană a trei rulări separate în procese diferite. selectolax a surclasat BeautifulSoup fără drept de apel și a ieșit la egalitate cu lxml în sarcina completă — apoi a pierdut etapa de parsare pură în fața lui lxml. Toate cifrele de mai jos sunt provizorii și provin de pe o singură mașină (macOS arm64, Python 3.14.2); scripturile sunt comise, deci merită să le rulezi și tu înainte să mă citezi.
Ce este, de fapt, selectolax — și ce nu este
selectolax este un binding Python pentru două motoare C — Modest și Lexbor — care parsează HTML5 și îl interoghează cu selectori CSS. Nu este crawler, nu este browser și nu este un „scraper” în sensul de buton-click. Este componenta pe care i-o dai după ce ai obținut deja HTML-ul. Formula scurtă a maintainerului este: „Un parser HTML5 rapid cu selectori CSS, scris în Cython, folosind motoarele Modest și Lexbor.”
Există două backend-uri, iar diferența contează mai mult decât lasă documentația să se înțeleagă:
LexborHTMLParser(motorul Lexbor) — varianta pe care README-ul o recomandă din 2024.HTMLParser(motorul Modest) — varianta originală, al cărei C library de bază „nu mai este întreținută”, după același README.
Înainte să trecem la viteză, merită câteva repere. La momentul snapshot-ului repo din 2026-07-10, selectolax avea 1.653 stele, iar ultima versiune era v0.4.10 (mai 2026), iar PyPI îl limitează la Python >=3.9,<3.15. Instalarea este partea cea mai puțin dramatică a acestui review: pip install selectolax a descărcat un wheel precompilat cp314 de 2,3 MB și a funcționat imediat pe Python 3.14 — fără download de browser, fără pas de doctor, fără compilare. Acesta este avantajul liniștit al unui parser pur în fața unui instrument bazat pe browser: se importă și rulează.
Mai există și o nuanță de licențiere pe care e bine s-o menționez acum, nu s-o ascund la final: binding-ul Python este MIT, dar wheel-ul include și motoarele compilate, iar acestea vin cu propriile licențe — Modest este LGPL-2.1, Lexbor este Apache-2.0. Așadar, „selectolax este MIT” este adevărat pentru codul Python, dar incomplet pentru binarul pe care îl livrezi efectiv. Dacă echipa ta juridică verifică componentele redistribuite, acesta este detaliul care contează.
Întrebarea despre viteză, răspunsă cu cifre reale
Iată sarcina pe care am cronometrat-o: parsează șirul HTML, extrage textul din fiecare <h3 class="title">, apoi extrage fiecare href din <a>. Latența este mediană, în milisecunde, calculată ca mediană între trei rulări separate în procese diferite; variația între rulări a rămas sub ~5% pentru parserele bazate pe C în majoritatea cazurilor. Înainte de a cronometra orice celulă, rezultatul fiecărui parser a fost redus la un hash de conținut, astfel încât un parser care ar fi făcut mai puțină muncă fără să spună asta să fie detectat și eliminat — pe aceste pagini, toate cele șase au coincis la fiecare dimensiune, deci comparația este cu adevărat corectă. Datele complete sunt în bench_parse.json, comis în repo.

| Pagină | selectolax (Lexbor) | selectolax (Modest) | lxml | parsel | BS (lxml) | BS (html.parser) |
|---|---|---|---|---|---|---|
| 1 KB | 0.027 | 0.029 | 0.036 | 0.044 | 0.281 | 0.323 |
| 10 KB | 0.160 | 0.171 | 0.166 | 0.228 | 1.705 | 2.049 |
| 100 KB | 1.464 | 1.565 | 1.423 | 2.020 | 16.5 | 20.6 |
| 1 MB | 14.901 | 16.9 | 14.177 | 20.9 | 181.9 | 232.6 |
| 10 MB | 159.9 | 247.9 | 172.9 | 231.9 | 2261.6 | 2788.7 |
În raport cu BeautifulSoup: cam 12-17x, iar legenda populară subestimează diferența
Dacă transformi cifrele în rapoarte, selectolax-Lexbor ajunge la aproximativ 12x mai rapid decât BeautifulSoup(html.parser) pe o pagină de 1 KB, urcând spre ~17x la 10 MB, și cam 10-14x mai rapid decât BeautifulSoup(lxml) pe același interval. Cifra care circulă online — „selectolax este cam de 4-5 ori mai rapid decât BeautifulSoup” — este prea mică dacă compari cu html.parser și devine aproximativ corectă doar pentru BeautifulSoup bazat pe lxml. Multiplicatorul real depinde de ce variantă de BeautifulSoup folosești și cât extragi din fiecare pagină.
Asta se aliniază și cu propriul benchmark din README, care sugerează un avantaj de 25,5x față de BeautifulSoup(html.parser). Niciuna dintre cifre nu este greșită. Sarcina din README (titluri, linkuri, scripturi și meta din homepage-uri mici) face mai puțină extracție pe pagini mici, ceea ce amplifică overhead-ul per-parsare al BeautifulSoup. Într-o formulare mai utilă, selectolax este cam de 10-15x mai rapid decât BeautifulSoup pentru o muncă realistă de parsare și extracție, iar pe pagini foarte mici și extracții mai reduse poate fi și mai mult.
Dacă acum te lovești de un cod BeautifulSoup care toacă pagini una după alta, aceasta este migrarea care se amortizează singură. Cazul acesta nu e controversat. Următorul este.
În raport cu lxml: egalitate — iar lxml câștigă partea pe care toată lumea uită s-o separe
Uită-te din nou la rândurile de 100 KB și 1 MB. Lexbor și lxml sunt la mai puțin de ~5% diferență, intervalele lor pe rulări se suprapun, iar după metodologia mea asta înseamnă egalitate — fără câștigător, fără „mai rapid”. Singurul caz în care selectolax se desprinde clar este pagina de 10 MB (159,9 ms față de 172,9 ms, un avantaj de 8,1% cu intervale care nu se suprapun). Deci, în sarcina completă, selectolax egalează lxml și îl depășește doar pe documentele foarte mari.

Apoi am separat construirea arborelui de interogarea CSS, iar rezultatul se inversează într-un mod pe care multe articole îl omit. La parsarea pură, fără nicio interogare, lxml a fost constant cu ~33-34% mai rapid decât selectolax-Lexbor pe această mașină — 77,9 ms față de 116,6 ms pe pagina de 10 MB. În sarcina completă, cele două converg oricum, iar ipoteza mea de lucru (nu ceva demonstrat printr-un experiment de atribuire) este că, pe aceste pagini, interogarea CSS reprezintă doar o mică parte din timp, așa că avantajul de parsare al lui lxml se diluează până când totalurile se întâlnesc.
Aceasta este afirmația cea mai ușor de contestat din tot review-ul, și vreau să fiu foarte clar de ce. Ea inversează înțelepciunea convențională, iar singurul benchmark public pe care l-am găsit și care izolează parsarea pură — aows.jpt.sh — raportează opusul, adică selectolax fiind cam de 4x mai rapid. Așa că am limitat interpretarea: rezultatul este pe o singură platformă (macOS arm64, Python 3.14, wheel-uri cp314 precompilate — nu am testat Linux x86_64 și nici build din sursă), a fost verificat pe patru dimensiuni de pagină și s-a menținut peste tot, iar apoi a fost re-verificat cu două API-uri diferite de lxml pentru a exclude un artefact de API. Ambele API-uri lxml au fost mai rapide decât selectolax-Lexbor la fiecare dimensiune. Nu prezint „lxml parsează mai repede” ca adevăr definitiv — îl prezint ca rezultat al propriului meu benchmark, cu scriptul atașat, în contrast cu majoritatea cifrelor publicate. Rulează-l și pe hardware-ul tău.
Încă o felie: la interogarea a 100.000 de <a> pe o pagină plată, lxml și selectolax-Modest ies la egalitate (33,30 ms vs 34,19 ms, cu intervale suprapuse), iar selectolax-Lexbor rămâne în urmă cu ~15%. Ce au în comun toate cele trei motoare C este că sunt de 5-7 ori mai rapide decât parsel sau BeautifulSoup la selecția în masă, unde modelul bazat pe obiecte Python pentru fiecare nod este adevăratul cost. Așadar, afirmația „selectolax este cel mai rapid la selecția CSS în masă” nu stă în picioare nici ea — Modest doar egalează lxml, iar Lexbor pierde în fața lui.
Concluzia pe care aș susține-o cu adevărat: avantajul selectolax față de lxml nu este o viteză generală, în toate situațiile. Câștigă doar pe documentele foarte mari. Argumentul lui real stă în altceva — ergonomia API-ului, comportamentul pe input murdar și CSS-ul modern — și exact acolo intră restul review-ului.
Memorie și pornire la rece: clasifică după RSS, nu după profilerul tău
Memoria este punctul în care trebuie să-mi corectez propriile cifre anterioare, iar corecția este esențială. Măsurată ca diferență de RSS pe pagina de 10 MB, cu tracemalloc dezactivat, BeautifulSoup consumă cam de 1,5-1,8x mai multă memorie decât selectolax sau lxml — intervalul merge de la 1,51x (BS-lxml la 218,4 MB vs Lexbor la 144,6 MB) până la 1,75x la capătul superior. selectolax și lxml se află în aceeași categorie de consum redus; lxml este cel mai economic după RSS.

O versiune anterioară a mea raporta „~3x”, iar cifra aceea era greșită dintr-un motiv instructiv: a fost măsurată cu tracemalloc activ, iar contabilizarea per-allocare din tracemalloc dublează aproximativ RSS-ul aparent al parserului care alocă cel mai mult. Așa că un avertisment pentru oricine măsoară memoria parserelor: clasifică după RSS, cu profilerul oprit. Dacă folosești peak-ul tracemalloc pentru a ierarhiza parser-ele, obții rezultate greșite mai ales pentru motoarele bazate pe C — în cazul acesta, selectolax-Lexbor părea mai greu decât Modest, deși în RSS real sunt apropiate. BeautifulSoup este într-adevăr cel mai gurmand aici; doar că nu este de 3x mai mare, așa cum sugera instrumentul contaminat.
Pornirea la rece contează, chiar dacă nu dramatic: selectolax se importă în aproximativ 14 ms, cam la același nivel cu lxml și de ~2,3x mai repede decât bs4 sau parsel. Dacă livrezi un CLI sau o funcție serverless unde timpul de import contează la fiecare invocare, diferența asta merită luată în seamă.
Acoperirea selectoarelor CSS: solidă, dar cu câteva găuri reale
Acoperirea CSS a fost testată pe o matrice de 41 de cazuri, fiecare selector fiind verificat pe un fixture cu răspuns corect cunoscut, plus o trecere deliberată de provocare, construită ca să rupă motorul Lexbor. Fiecare caz a rulat în propriul subprocess, lucru care s-a dovedit necesar — unul dintre ele prăbușește întregul interpreter. Rezultatele:

| Motor | PASS | GREȘIT | NESUPORTAT | PROCESS_ABORT |
|---|---|---|---|---|
| soupsieve | 41 | 0 | 0 | 0 |
| selectolax Lexbor | 39 | 0 | 2 | 0 |
| lxml (cssselect) | 37 | 1 | 3 | 0 |
| parsel (cssselect) | 37 | 1 | 3 | 0 |
| selectolax Modest | 35 | 3 | 2 | 1 |
Când intră în scenă selectorii ostili, Lexbor nu mai este câștigătorul absolut — soupsieve este, cu 41/41 curate, față de 39/41 pentru Lexbor. Cele două eșecuri ale Lexbor sunt :lang(en) și :dir(rtl), pe care le respinge cu eroare de parsare. În rest este impecabil, inclusiv pentru :has(), :is(), :where() și atribute fără diferențiere între majuscule și minuscule.
Unde Lexbor chiar strălucește este în comparație cu stack-ul cssselect. Selectorul vedetă din README — div > :nth-child(2n+1):not(:has(a)) — returnează setul corect atât pe ambele backend-uri selectolax, cât și pe soupsieve, dar returnează setul greșit pe lxml și parsel, fără să afișeze vreo eroare. Un scraper care copiază acel selector în Scrapy sau parsel va obține rezultate greșite, dar fără avertisment. Ca să fiu precis: cssselect a parsează :has() încă din versiunea 1.2.0 (2022), iar eu am testat 1.4.0, deci aici nu vorbim despre „nesuportat”, ci despre „suportat, dar evaluat greșit în combinație”. Comportamentul silențios de set greșit pentru acest compound nu apare în tracker-ul cssselect, care documentează limitele lui :has() ca erori ridicate. Lexbor gestionează și flag-ul de atribut case-insensitive [data-role="LEAD" i], pe care cssselect îl respinge direct.
Totuși, două lipsuri vor decide migrațiile. selectolax nu are deloc XPath — niciun backend nu expune xpath() — și nici pseudo-elementele ::text / ::attr(), pentru că acestea sunt o extensie parsel/Scrapy, nu CSS real. Dacă scraper-ele tale actuale se bazează pe XPath, aceasta este cea mai mare barieră: va trebui să rescrii selectorii, nu doar să schimbi biblioteca. Pe de altă parte, Lexbor oferă pseudo-clasa :lexbor-contains("text" i) pentru matching text case-insensitive, pe care nici lxml, nici parsel, nici CSS standard nu o au, și funcționează exact cum este documentată.
Robustitate pe HTML urât, adică exact locul în care selectolax își câștigă dreptul de a fi folosit
Scrapingul real înseamnă să arunci gunoi într-un parser și să speri că nu se îneacă. Am rulat 18 inputuri adversariale, iar aceasta este categoria în care argumentul selectolax în fața lui lxml este cel mai puternic.
Dacă îi dai lui lxml.html.fromstring un șir gol sau doar spații, el aruncă ParserError("Document is empty"). Ambele backend-uri selectolax returnează, în schimb, un arbore valid, gol. Pentru un scraper care iterează printr-o listă de URL-uri unde unele răspunsuri sunt goale, asta înseamnă un try/except mai puțin în jurul întregului flux. selectolax a trecut și prin 100.000 de elemente fără stack overflow.
Încărcarea foarte adâncă a fost cel mai clar punct de separare. La 1.000 și 5.000 de niveluri de <div> imbricat, lxml elimină în tăcere conținutul cel mai adânc, în timp ce selectolax îl păstrează. libxml2 limitează adâncimea de parsare la aproximativ 256 de niveluri și taie arborele fără eroare, astfel că textul cel mai adânc devine pur și simplu inaccesibil. Ambele backend-uri selectolax returnează arborele complet. Este imaginea în oglindă a capcanei <template> despre care voi vorbi imediat: acolo Lexbor elimină conținutul pe care ceilalți îl păstrează; aici lxml elimină conținutul pe care selectolax îl păstrează.
Nu toate celulele au fost un succes. Backend-ul Modest oprește întregul interpreter Python cu un SIGABRT când întâlnește :dir() — nu o excepție pe care s-o poți prinde, ci un crash dur al procesului. Este o avertizare reală pentru oricine încă folosește backend-ul vechi, și exact genul de lucru care rămâne invizibil până când îți doboară un job de producție la 3 dimineața.
Două capcane de pierdere silențioasă a datelor pe care trebuie să le știi înainte de lansare
Niciuna dintre acestea nu este o descoperire nouă — ambele sunt documentate upstream — dar ambele pot costa date reale, fără zgomot, și nu sunt explicate clar în README.
Lexbor omite <a> din interiorul lui <template>
Pe pagina MDN live pe care am testat-o, selectolax-Lexbor a găsit 497 de linkuri, în timp ce lxml, ambele backend-uri BeautifulSoup și chiar backend-ul Modest al lui selectolax au găsit 508. Cele unsprezece lipsă erau un comutator de limbă și un link către discuții, ambele aflate în elemente <template> (pagina folosește componente web Lit).

Cauza este legitimă: conform specificației HTML5, conținutul din <template> este parsat într-un fragment inert separat, nu în DOM-ul normal, iar Lexbor respectă asta strict — tree.css("a") nu coboară în conținutul template-ului. lxml, ambele backend-uri BeautifulSoup și Modest aplatizează conținutul template-ului în arborele principal, deci găsesc acele linkuri. Aceasta este o problemă deschisă documentată (selectolax#146, cu sursa în motor la lexbor#170), iar ambele interpretări sunt apărate în mod rezonabil — Lexbor este, probabil, mai corect din perspectiva specificației. Dar un developer care folosește backend-ul recomandat poate rata acele date fără niciun avertisment. Și inversul merită spus: celelalte parsere expun conținut inert din template pe care un browser nu îl afișează, deci îți pot livra date-fantomă pe care utilizatorul nu le vede. Ieșirea sigură de avarie este backend-ul Modest, sau o altă bibliotecă, pentru pagina respectivă.
Bytes non-UTF-8 corup în tăcere .text()
Dacă îi dai lui selectolax bytes care nu sunt UTF-8 valid, parsarea reușește — coruperea apare mai târziu și e mai rea decât un crash curat. La "<p>café éè</p>".encode("latin-1"), .text() în Lexbor returnează caractere de înlocuire, .text() în Modest elimină în tăcere bytes-ii problematici, iar ambele motoare aruncă UnicodeDecodeError doar când accesezi .html. Binding-ul decodează strict ca UTF-8 la citire, nu la parsare. Aceasta este legată de o problemă cunoscută selectolax privind strictețea la encode/decode.
Corecția este o singură linie și ar trebui să devină reflex: decodează tu bytes-ii înainte — LexborHTMLParser(resp.content.decode("latin-1")) — iar ambele motoare vor returna corect 'café éè'. În practică, dă-i mereu lui selectolax un str, niciodată bytes brute care nu sunt UTF-8. README-ul nu spune asta explicit.
Dimensiuni pentru producție (o singură observație, deci tratează-le ca direcții, nu ca adevăruri finale)
Rezultatele de mai jos le-am măsurat o singură dată, nu în trei rulări, deci le marchez ca semnale, nu ca cifre definitive.
Scalarea pe thread-uri este partea interesantă. Parsând o pagină de 1 MB de 48 de ori pe patru thread-uri, selectolax a arătat un speedup de ~3,5-3,9x la nivel de wall-clock — semn empiric că biblioteca eliberează GIL-ul în timpul parsării C — în timp ce BeautifulSoup(lxml) a devenit de câteva ori mai lent în thread-uri, semn că munca se serializează pe GIL. lxml a fost undeva la mijloc și rezultatul a rămas neconcludent. Pentru era free-threading spre care se îndreaptă Python, faptul că selectolax se poate paraleliza între thread-uri, acolo unde BeautifulSoup nu poate, este un avantaj real, chiar dacă provizoriu. Este un singur număr, pentru o singură dimensiune de pagină, iar mecanismul este o ipoteză, nu ceva confirmat prin instrumentarea codului C.
Despre leak-uri: pe 2.000 de iterații de parse-extract-drop la 1 MB, niciunul dintre cele trei parsere nu a arătat creșterea liniară de RSS specifică unui leak — fiecare s-a stabilizat într-o bandă limitată de working set. Am încredere în acest rezultat tocmai pentru că am trecut prin același instrument un subiect de calibrare despre care știam că are leak, iar acesta a urcat la +198 MB exact cum era proiectat, ceea ce dovedește că instrumentul putea vedea un leak și pur și simplu nu a găsit unul în parsere. Iar un node handle păstrat viu după ce arborele său părinte a ieșit din scope a rămas utilizabil, fără segfault. Toate sunt observații unice, niciuna nu vine dintr-un soak de mai multe ore.
Unde se potrivește selectolax — și unde pasează mai departe
Tot ce am spus mai sus privește o singură sarcină: transformarea HTML-ului pe care îl ai deja în date structurate, rapid. selectolax excelează la asta. Ce nu face intenționat este să aducă pagina, să redea JavaScript-ul, să rotească proxy-uri, să rezolve CAPTCHAs sau să decidă ce elemente vrei. Toate acestea rămân în continuare treaba codului tău. selectolax este stratul de parsare și nu pretinde să fie mai mult.
Aici apare linia de demarcație unde un serviciu gestionat de extracție stă deasupra unui parser, nu în locul lui. Dacă preferi să nu construiești și să nu întreții singur întregul stack fetch-render-anti-bot-extract, Thunderbit expune asta prin API, MCP server și CLI — POST /distill transformă o pagină în Markdown curat, iar POST /extract returnează JSON structurat, aliniat pe schemă, cu randare JS și protecție anti-bot incluse. Este un alt strat al problemei: ai folosi selectolax când ai deja HTML-ul și vrei viteză brută de parsare sub controlul tău, iar ceva de genul API-ului, MCP server-ului sau CLI-ului Thunderbit când vrei ca fetch-ul și extracția să fie gestionate pentru tine și să primești doar date structurate înapoi. Nu este un substitut — este un alt nivel în același stack.
Încearcă Thunderbit pentru extragerea datelor web
Avantaje, dezavantaje și cine ar trebui să-l folosească
Unde câștigă selectolax:
- De aproximativ 12-17x mai rapid decât BeautifulSoup în sarcini realiste de parsare și extracție, stabil pe trei ordine de mărime ale paginii.
- Memorie redusă (nivelul lxml, cu ~1,5-1,8x mai puțin decât BeautifulSoup) și un import de ~14 ms.
- Rezistent pe inputurile care rup lxml — gol, whitespace și imbricare patologic de adâncă.
- CSS modern, inclusiv
:has(),:is(),:where(), atribute case-insensitive și:lexbor-contains()specific Lexbor. - DOM sigur la
None: elementele lipsă întorcNonesau[]în loc să arunce excepții, iar arborele poate fi modificat și serializat din nou. - Întreținere activă (v0.4.10, mijlocul lui 2026) și instalare banală.
Unde nu câștigă:
- Nu este, în general, mai rapid decât lxml — egalitate pe sarcina completă și pierde la parsarea pură în benchmark-ul meu.
- Nu are XPath și nici
::text/::attr()— o barieră reală de migrare pentru scraper-ele bazate pe XPath. - Două capcane de pierdere silențioasă a datelor: conținutul
<template>în Lexbor și bytes non-UTF-8 prin.text(). - Backend-ul Modest este legacy și va produce SIGABRT la
:dir(). - Toate cifrele de aici sunt pe o singură platformă (macOS arm64, Python 3.14) și sunt provizorii.
Ar trebui să folosești selectolax? Da, dacă vrei viteza de parsare de clasă lxml, dar cu un API mai prietenos, sigur pe None, și un comportament mult mai bun pe input gol sau stricat — și ești dispus să rămâi în teritoriu CSS-only. Dacă baza ta de cod este construită pe XPath, costul rescrierii este real și merită evaluat onest. Iar dacă urmărești „cel mai rapid parser” în absolut, răspunsul corect din acest benchmark este că selectolax și lxml sunt suficient de apropiate încât diferența să se decidă după ergonomie și robustețe, nu după viteză brută. Și, sincer, acesta e un motiv mai bun pentru a alege un tool.
Încearcă Thunderbit pentru extragerea datelor web Get Started Free
Întrebări frecvente
Este selectolax mai rapid decât BeautifulSoup?
Da, clar — aproximativ de 12-17x mai rapid decât BeautifulSoup(html.parser) și de 10-14x mai rapid decât BeautifulSoup(lxml) într-o sarcină realistă de parsare și extracție, menținându-se stabil de la pagini de 1 KB la 10 MB (macOS arm64, Python 3.14). Cifra des citată de „4-5x” subestimează diferența față de html.parser.
Este selectolax mai rapid decât lxml? Nu în mod general. În sarcina completă de parsare și extracție, cele două sunt la egalitate la 100 KB și 1 MB, iar selectolax câștigă doar pe pagina de 10 MB. La parsare pură, fără interogări, lxml a fost de fapt cu ~33-34% mai rapid pe mașina mea — un rezultat care contrazice consensul și pe care îl tratez ca fiind specific platformei, deci verifică-l și pe hardware-ul tău.
Ar trebui să folosesc backend-ul Lexbor sau Modest?
Lexbor, în aproape toate cazurile — este motorul întreținut, complet din punct de vedere funcțional, recomandat în README, cu o acoperire CSS mai bună. Singura excepție este o pagină care ascunde conținut în elemente <template>, unde comportamentul corect al Lexbor elimină acel conținut, iar Modest îl păstrează întâmplător. Modest are și margini ascuțite, inclusiv un crash dur al interpreterului la :dir().
Suportă selectolax XPath?
Nu. Niciun backend nu expune metoda xpath() — selectolax este doar CSS. Dacă scraper-ele tale depind de XPath, migrarea înseamnă rescrierea selectorilor, iar acesta este cel mai mare cost al trecerii de la un stack bazat pe lxml sau parsel la selectolax.
De ce îmi apare outputul selectolax stricat sau lipsesc elemente?
De obicei sunt doi vinovați. Dacă textul apare cu caractere de înlocuire sau fără diacritice, probabil ai trimis bytes brute care nu sunt UTF-8 — decodează-i într-un str înainte (resp.content.decode("latin-1")) și abia apoi parsează. Dacă lipsesc linkuri sau elemente pe un site modern, e posibil să fie în interiorul tagurilor <template> pe care backend-ul Lexbor nu le traversează; treci pe Modest sau pe alt parser pentru acea pagină.


