安装因编译报错时需改装 pip install selectolax[cython];从 GitHub 装开发版要 git clone --recursive 拉取子模块;旧版本配新版 Python 容易编译失败

selectolax
rushterMIT活跃维护基于 Modest 和 Lexbor 引擎的 Python HTML5 解析库,解析速度快,支持 CSS 选择器,适合网页抓取时高效提取页面数据。
Python binding to Modest and Lexbor engines. Fast HTML5 parser with CSS selectors for Python.
pip install selectolaxREADME 未说明,纯 CPU 解析,无 GPU 或显存要求
用 Cython 封装 Lexbor 引擎的 Python HTML5 解析器,带 CSS 选择器,解析速度远超 Beautiful Soup
基于 Modest 和 Lexbor 引擎的 Python HTML5 解析库,解析速度快,支持 CSS 选择器,适合网页抓取时高效提取页面数据。
核心能力
- 基于 Lexbor 引擎解析 HTML5,Cython 编写
- 支持 css_first 和 css 按 CSS 选择器取节点
- 支持 nth-child、:not、:has 等高级选择器
- 提供 lexbor-contains 伪类按文本内容匹配
- 可读取节点 text、attributes、tag、parent 和 html
容易踩的坑
- v1.0.2最新正式版2026-10-22 · 2026-10-22 15:17 UTC
Bugfix release for 1.0.1.
- Fix
insert_child(),insert_before(),insert_after()andreplace_with()move nodes. - Add the
moveparameter toinsert_child(),insert_before(),insert_after()andreplace_with(). Passmove=Trueto move the node instead of copying it: the node is removed from its current position and placed in the new one. A node taken from another parser is copied into the target document and removed from the document it came from. The default ismove=False, which keeps the copying behaviour.
- Fix
- v1.0.12026-10-17 · 2026-10-17 17:53 UTC
查看更新说明
- Add the
scriptingoption toLexborHTMLParser, which parses<noscript>the way a browser with scripting enabled does: its content becomes raw text, so a<noscript>in<head>no longer pushes the head elements after it into<body>. The default is unchanged. - Add
template_fragments()for reaching the content of<template>elements which are ignored by HTML5 compliant parsers. - Do not replace
<-undef>it not longer possible to get it. - The internal
<html>wrapper of an HTML fragment is no longer reported as theparentof the fragment's top-level nodes. create_tag()no longer returnsNonefor the tags whose start tag the HTML parser drops (html,head,body,caption,col,colgroup,frame,frameset,tbody,td,tfoot,th,thead,tr).- Fix
inner_htmlcovering only the first top-level node of an HTML fragment. - Improve the speed of comment extraction
- Improve the speed of
len(attrs)by counting the attribute list directly - Fix encoding initialization when
encoding=True.
- Add the
- v1.0.02026-10-03 · 2026-10-03 15:01 UTC
查看更新说明
This release contains breaking changes. It focuses on speed improvements and corner cases.
The main change is that the Modest backend is no longer available. It is outdated and unmaintained since 2021, contains bugs, and does not follow modern HTML5 standards. We have supported the Lexbor backend since 2021, and we have recommended it for more than 3 years. It gets updated every month and follows all the modern HTML5 standards while being faster on a lot of tasks.
The second is that
parse_fragment()is gone. It re-implemented fragment parsing by guessing whether the input was a document or a fragment;LexborHTMLParser(html, is_fragment=True)already does this properly, so the guessing layer has been removed.The rest of the changes fix corner cases where the bugs were happening rarely, usually when heavily modifying the tree.
- Breaking: Remove the Modest backend.
selectolax.parseris now a stub that raisesImportErroron import. Use the lexbor backend (from selectolax.lexbor import LexborHTMLParser) instead. - Breaking: Remove
parse_fragment(). - Breaking: Fix
css_matchesandany_css_matchesmissing matches outside the first top-level node of an HTML fragment. They now search the same scope ascss. - Breaking: Fix
tagsandstrip_tagsdoing nothing on an HTML fragment.tagsreturned an empty list andstrip_tagsremoved nothing, because the fragment was not reachable from the document node. - Breaking: Fix the internal
<html>wrapper of an HTML fragment being reported as a match. - Breaking: Fix
scripts_containandscript_srcs_containmissing matches outside the first top-level node of an HTML fragment. They now search the same scope ascss. - Breaking: Fix
scripts_containandscript_srcs_containanswering from another scope's cached result. The cache is keyed by the node the search is rooted at rather than the node it was called on. - Breaking: Fix
select()missing matches outside the first top-level node of an HTML fragment. It now searches the same scope ascss. - Breaking: Fix
traverse()covering only the first top-level node of an HTML fragment, and yielding nothing when the fragment starts with a text node. - Breaking: Fix
attribute_longer_thanandany_attribute_longer_thanreturning inconsistent results - Breaking:
attributesandattrsnow report an attribute's qualified name instead of its local name. An element carrying bothhrefandxlink:hrefused to collapse them into a singlehrefkey. - Breaking: Fix
iter()skipping the remaining children when a node is removed during iteration - Breaking: Fix an HTML fragment whose first node is text dropping the rest of the fragment.
LexborHTMLParser('a<span>s</span>', is_fragment=True).text()returned'a'instead of'as'. - Fix
text()silently returning truncated text instead of raising when a fragment fails to be collected. - Fix
scripts_containandscript_srcs_containsometimes returning wrong results due to HTML mutations. - Fix a single undecodable byte in an untrusted document making
html,inner_html,html_pretty,attributes,attrs,id,tag,text_lexborandtext_contentraiseUnicodeDecodeError. Bytes Lexbor passes through verbatim are now substituted with U+FFFD, the waytext()already did. - Fix
text_lexborsometimes holding temporary memory longer than needed - Improve memory consumption, potential stack overflow and slow extraction in
merge_text_nodes(). It is now up to 10 times faster. - Improve speed of
__eq__ - Improve speed of
attrs.items()andattrs.values(). - Fix the
inner_htmlsetter attaching element children to non-element nodes - Fix
headandbodydangling after settinginner_htmlon the<html>element - Fix the
inner_htmlsetter freeing the replaced children - Fix
rootgoing stale on an HTML fragment. - Fix a se
- Breaking: Remove the Modest backend.
- v0.4.132026-09-29 · 2026-09-29 08:20 UTC
查看更新说明
- Support lexbor-only builds with
--disable-modest - Importing
selectolaxno longer automatically importsselectolax.parserandselectolax.lexbor - Update lexbor
- Support lexbor-only builds with
- v0.4.122026-09-18 · 2026-09-18 07:56 UTC
查看更新说明
- Add
optionsparameter toLexborHTMLParserto pass Lexbor document parsing options (for example,LexborDocumentOptions.WO_EVENTSto disable mutation events). Fixes #221. - Fix
LexborHTMLParser.clone()losing nodes for empty HTML fragments - Allow empty elements in
text_lexbor. Fixes #220. - Update lexbor
- Add
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。

A fast HTML5 parser with CSS selectors, written in Cython, using the Lexbor engine.
Installation
From PyPI using pip:
pip install selectolax
If installation fails due to compilation errors, you may need to install Cython:
pip install selectolax[cython]
This usually happens when you try to install an outdated version of selectolax on a newer version of Python.
Development version from GitHub:
git clone --recursive https://github.com/rushter/selectolax
cd selectolax
pip install -r requirements_dev.txt
python setup.py install
How to compile selectolax while developing:
make clean
make dev
Basic examples
Here are some basic examples to get you started with selectolax:
Parsing HTML and extracting text:
from selectolax.lexbor import LexborHTMLParser
html = """
<h1 id="title" data-updated="20201101">Hi there</h1>
<div class="post">Lorem Ipsum is simply dummy text of the printing and typesetting industry. </div>
<div class="post">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>
"""
tree = LexborHTMLParser(html)
print(tree.css_first('h1#title').text())
# 'Hi there'
print(tree.css_first('h1#title').attributes)
# {'id': 'title', 'data-updated': '20201101'}
print([node.text() for node in tree.css('.post')])
# ['Lorem Ipsum is simply dummy text of the printing and typesetting industry. ',
# 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.']
Using advanced CSS selectors
from selectolax.lexbor import LexborHTMLParser
html = "<div><p id=p1><p id=p2><p id=p3><a>link</a><p id=p4><p id=p5>text<p id=p6></div>"
selector = "div > :nth-child(2n+1):not(:has(a))"
for node in LexborHTMLParser(html).css(selector):
print(node.attributes, node.text(), node.tag)
print(node.parent.tag)
print(node.html)
# {'id': 'p1'} p
# div
# <p id="p1"></p>
# {'id': 'p5'} text p
# div
# <p id="p5">text</p>
Using lexbor-contains CSS pseudo-class to match text
from selectolax.lexbor import LexborHTMLParser
html = "<div><p>hello </p><p id='main'>lexbor is AwesOme</p></div>"
parser = LexborHTMLParser(html)
# Case-insensitive search
results = parser.css('p:lexbor-contains("awesome" i)')
# Case-sensitive search
results = parser.css('p:lexbor-contains("AwesOme")')
assert len(results) == 1
assert results[0].text() == "lexbor is AwesOme"
Simple Benchmark
- Extract title, links, scripts and a meta tag from main pages of top 754 domains. See
examples/benchmark.pyfor more information.
| Package | Time |
|---|---|
| Beautiful Soup (html.parser) | 61.02 sec. |
| lxml / Beautiful Soup (lxml) | 9.09 sec. |
| html5_parser | 16.10 sec. |
| selectolax (Lexbor) | 2.39 sec. |
Links
- Changelog
- selectolax API reference and examples
- Video introduction to web scraping using selectolax
- How to Scrape 7k Products with Python using selectolax and httpx
- Lexbor benchmark
- Python benchmark
- Another Python benchmark
- Universal interface to lxml and selectolax
License
- lexbor engine — Apache-2.0 license
- selectolax - MIT
Contributors
Thanks to all the contributors of selectolax!