先说结论
Scrapling(作者 D4Vinci / Karim Shoair,BSD-3,PyPI 当前 0.4.8,支持 Python 3.10–3.13,GitHub 7.6w+ star)是我近期见到的,把「站点改版后选择器失效」和「被反爬 403/429」这两件最磨人的事,用一套 API 统一掉的自适应抓取框架。
它最核心的判断是:很多抓取方案默认「网站结构不会变」,而现实是它一定会变。 Scrapling 用自适应选择器去对抗这种不确定性,而不是靠你每次手动改 selector 去补。
Fetcher 三层,怎么选
Scrapling 的抓取不是一款,而是三款,按被反爬的强度分层:
| 层 | 类 | 底层 | 适用 |
|---|---|---|---|
| 纯 HTTP | Fetcher | requests/httpx 系,可伪造 TLS 指纹、支持 HTTP/3 | 静态页,最快,10–100x 比浏览器快 |
| 浏览器 | DynamicFetcher | Playwright Chromium/Chrome | JS 渲染 SPA、需要等网络 idle |
| 反反爬 | StealthyFetcher | 真实 Chromium + 反指纹补丁 | 遇到 Cloudflare Turnstile / Headless 检测 |
我的排序依据很简单:先用最快的,被挡再升级。 别一上来就开浏览器,那是最贵的选择。官方给的决策树也是这个思路:
- 静态 HTML?用
Fetcher,最快。 - 需要执行 JS?用
DynamicFetcher。 - 被挡了?用
StealthyFetcher。 - 需要跨请求保持 cookie/会话?用对应的
FetcherSession / DynamicSession / StealthySession。
adaptive 选择器:这套框架的真正卖点
大多数人第一次用 Scrapling,会被 StealthyFetcher 吸引,但那只是「反反爬」这一层。真正区别于 requests + BeautifulSoup 的地方,是 adaptive 这个机制。
from scrapling.fetchers import Fetcher, AsyncFetcher, StealthyFetcher, DynamicFetcher
StealthyFetcher.adaptive = True
p = StealthyFetcher.fetch('https://example.com', headless=True, network_idle=True)
# 抓取时保存当前位置信息,站点改版后还能定位到元素
products = p.css('.product', auto_save=True)
# 等网站结构变了,再传 adaptive=True 重新定位
products = p.css('.product', adaptive=True)
它的原理,是用智能相似度算法记录元素在当前 DOM 里的「位置指纹」(包括周围结构、标签、文本特征),而不是只死记一个 .product 这个 class 名。这样当网站把 class 改掉、把层级挪了一层时,它还能靠「长得很像的那个元素」把你重新定位过去。
这是要付出代价的。 自适应不是零成本:每次 adaptive 都要跑相似度计算,比直接 .css() 慢;而且如果页面里相似元素太多,会定位到「貌似正确但其实是别的」的元素,数据就错了。所以我的建议是:
- 初次抓取用
auto_save=True把位置指纹存下来; - 等真的收到站点改版、元素抓不到报错时,再开
adaptive=True; - 不要在每天都跑的高频任务里默认开 adaptive,除非你已经确认站点经常变。
StealthyFetcher 能过什么、不能过什么
StealthyFetcher 底层是一个打过补丁的真实 Chromium,做了几件事:
- 自动绕过 Cloudflare Turnstile / Interstitial;
- 处理 CDP runtime 泄漏、WebRTC 泄漏;
- 隔离 JS 执行、抹掉部分 Playwright 指纹和 headless 特征;
- 给 canvas 加噪,防指纹识别;
- 提供
real_chrome=True用本机安装的 Chrome,而不是 Chromium。
用起来很简单:
page = StealthyFetcher.fetch(
'https://protected-site.com',
headless=True,
solve_cloudflare=True, # 自动解 Turnstile
block_webrtc=True,
hide_canvas=True,
proxy='http://username:password@host:port',
)
但必须说清楚边界: 它解决的是「Cloudflare 这种基于浏览器指纹 + Turnstile 的防护」,以及「Headless 特征检测」。它不是万能的。下面的情况它帮不上忙,官方文档也直接承认:
- 验证码(CAPTCHA):官方明确「Cannot bypass」——你该做的是跳过,或走官方 API。
- 需要登录/鉴权的接口:官方建议「Do NOT bypass——用官方 API」。强行绕过登录属于灰色地带,不值得,也容易把账号弄挂。
- 企业级防护(Akamai、DataDome、Kasada、Incapsula):README 里 Scrapling 自己都说,这种级别它只负责 Cloudflare,更强防护要用第三方付费服务。
所以别把 StealthyFetcher 当「能扫一切」的银弹。它更适合的定位是:把你手头那些「普通反爬」的站点,从手工造指纹的泥坑里捞出来。
两点坑
1. disable_resources 能省资源,但可能让页面永远加载不完。
page = DynamicFetcher.fetch(url, disable_resources=True)
这个参数会阻断图片、字体等资源,能省流量、省代理用量,某些站点下甚至快 2x。但代价是:有的站点会因此永远不触发加载完成事件,你就卡在 network_idle 上等死。按需用,别默认开。
2. 装依赖不是一条 pip install scrapling 就完事。
抓取模式(Dynamic/Stealthy)需要浏览器,得额外跑:
pip install "scrapling[all]"
scrapling install # 下载/安装浏览器
playwright install chromium
如果你只要纯 HTTP 层,只装 scrapling 核心包就行,省不少体积。装什么取决于你要用哪层,这个取舍值得先想清楚。
什么时候别用它
- 你的目标站点是稳定的、纯静态、无反爬 → 直接 requests + 解析器,别引入一个带浏览器的框架,太重。
- 你要抓的是需要登录鉴权 / 付费内容 → 别硬绕,走官方 API。
- 你只是偶尔抓一次、没有批量 → 为了它装浏览器、学一套 API,不太划算。
Scrapling 的价值,是当你同时撞上「站点常改版 + 有反爬」这两个痛点时,用一套东西把复杂度吃掉。如果只需要其中一层的功能,用更轻的工具、或只用它的 Fetcher 层,才符合「宁可短而准」的原则。
说明:文中关于
adaptive的性能开销、disable_resources卡 loading 的具体表现,是基于官方文档和社区反馈整理,我未在自有环境逐站点实测。实际抓取时建议以你的目标站点为准,先小范围验证再全量跑。