首页
/ Scrapling:从单次请求到全站爬取的自适应 Web 抓取框架全面解析

Scrapling:从单次请求到全站爬取的自适应 Web 抓取框架全面解析

2026-09-06 10:08:39作者:冯爽妲Honey

Scrapling 是一个自适应 Web 抓取框架(adaptive Web Scraping framework),覆盖从“发一个 HTTP 请求解析几行数据”到“并行、多会话、可断点续爬的全站爬取”的完整场景。本篇基于仓库内的 俄语版项目主文档 展开,完整覆盖其核心特性、三类 Fetcher 与 Session 的用法、Spider 框架、CLI 与交互式 Shell、性能基准与安装配置,并结合仓库源码逐一印证关键 API 的真实实现位置与调用关系,帮助你在几行 Python 代码内搭建可长期运行的抓取系统。

项目定位:一个库解决三件事

从主文档的概述可以看出,Scrapling 的设计目标是“一件事不留妥协地做完”(one library, no compromises):

  1. 自适应解析器:其 parser 能学习网站结构的变化,当页面改版后自动“搬移”你之前保存过的元素选择位置——即 adaptive(自适应)机制;
  2. 抗反爬 Fetcher:内置的 Fetcher 系列开箱即用即可处理 Cloudflare Turnstile 等反机器人系统;
  3. Spider 框架:可规模化到并行、多会话的爬取,支持 Pause & Resume(暂停与恢复)与自动代理轮换。

仓库的模块结构也印证了这一分层:scrapling/engines(抓取引擎与浏览器底座)、scrapling/fetchers(三类 Fetcher 门面)、scrapling/spiders(爬虫框架)、scrapling/parser.py(解析器)、scrapling/core/storage.py(自适应存储)与 scrapling/cli.py(命令行与 Shell)。

核心特性总览

Spider 框架:Scrapy 风格的完整爬取框架

主文档列出的 Spider 能力,均可在 scrapling/spiders/ 目录中找到对应实现:

  • Scrapy 风格 API:通过 start_urls、异步 parse 回调与 Request/Response 对象定义 Spider,分别对应 request.pyresult.py
  • 并行爬取:可配置并发限制、按域名的速率限制与加载延迟,相关实现位于 throttle.py
  • 多会话支持:同一个 Spider 内可同时挂载 HTTP 会话与 stealthy 无头浏览器会话,按请求的 sid(session ID)路由到不同会话;
  • Pause & Resume:基于 Checkpoint 的爬取持久化,Ctrl+C 软停止、再次启动时从断点继续,实现见 checkpoint.py
  • Streaming 模式:通过 async for item in spider.stream() 边爬边消费结果,并附带实时统计;
  • 阻塞检测:自动识别被拦截的请求并按可定制逻辑重发;
  • AutoThrottle:Spider 根据站点响应速度自动调整每个域名的延迟,一旦遇到限速/封锁则倍增延迟(或遵循 Retry-After),恢复后再提速;
  • robots.txt 合规:可选的 robots_txt_obey 标志,遵循 DisallowCrawl-delayRequest-rate 指令并按域名缓存,实现在 robotstxt.py
  • 开发模式:首次运行把响应缓存到磁盘,后续运行直接回放,让你迭代 parse() 逻辑而不重复请求目标服务器(见 cache.py);
  • 内置模板CrawlSpider(基于规则的链接跟随)、SitemapSpider(sitemap/robots 驱动)、XMLFeedSpider/CSVFeedSpider(XML/RSS 与 CSV feed 遍历)、ShopifySpider(通过 Shopify JSON API 抽取整个商品目录,每个 variant 一条记录)——这些模板分别位于 crawler.pysitemap.pyfeed.pyshopify.py
  • LinkExtractor:独立的链接抽取原语,支持 allow/deny 模板、域名过滤、CSS/XPath 作用域限定、扩展名过滤与链接规范化(links.py);
  • 结果导出:内置 JSON/JSONL/CSV/XML 导出器,result.items.to_json()to_jsonl()to_csv()to_xml() 均可用,四个方法都定义在 result.py

Scrapling Spider 架构示意图

高级 Fetcher:三种抓取方式与 Session 体系

scrapling/fetchers/__init__.py 通过懒加载映射对外暴露了 10 个核心类(外加 ProxyRotator):

类别 类名 底层模块
HTTP 请求 Fetcher / AsyncFetcher / FetcherSession requests.py
动态渲染 DynamicFetcher / DynamicSession / AsyncDynamicSession chrome.py
隐身浏览器 StealthyFetcher / StealthySession / AsyncStealthySession stealth_chrome.py

fetchers/init.py 的源码结构看,所有 Fetcher 类都采用 __getattr__ 惰性导入,这意味着 import scrapling.fetchers 本身不会触发 playwright/curl_cffi 等重依赖加载,只有在真正访问某个类时才会导入对应模块。

各 Fetcher 的能力边界(来自主文档,并有源码佐证):

  • HTTP 请求(Fetcher):快速且“安静”的 HTTP 请求,可模拟浏览器的 TLS fingerprint、自定义请求头、使用 HTTP/3;
  • 动态加载(DynamicFetcher):基于 Playwright 的完整浏览器自动化,支持 Chromium 与本机 Google Chrome;
  • 反爬绕过(StealthyFetcher):指纹伪装与高级隐身,可自动化通过各类 Cloudflare Turnstile/Interstitial 挑战——solve_cloudflare 等参数在 stealth_chrome.py 中均有定义;
  • 会话管理FetcherSessionStealthySessionDynamicSession 用于在多个请求间维持 cookie 与状态;
  • 代理轮换:内置 ProxyRotator 支持循环或自定义策略,适用于所有会话类型,且每个请求都可单独覆盖代理(proxy_rotation.py);
  • 域名与广告屏蔽:屏蔽指定域名(含子域名)的请求,或启用内置广告拦截(约 3500 个已知广告/追踪域名,见 ad_domains.py);
  • DNS 防泄漏:可选 DNS-over-HTTPS,将 DNS 请求经 Cloudflare DoH 路由,防止走代理时发生 DNS 泄漏;
  • 远程浏览器:通过 cdp_url 连接已运行的浏览器(同机、异机或托管浏览器服务);executable_path 可把任意浏览器 Fetcher 指向自建 Chromium;
  • XHR 拦截:向 capture_xhr 传入 URL 模板后,页面加载期间所有匹配的 XHR/fetch 响应会被收集为 Response 对象挂在 response.captured_xhr 上,无需手工逆向站点 API;
  • 全量 async 支持:所有 Fetcher 与专用 async 会话类都提供异步版本。

Scrapling 交互式 Shell 中将 curl 请求转换运行的演示

自适应抓取与 AI 集成

  • 智能元素追踪:网站改版后基于相似度算法自动重新定位元素,parser.pyadaptive 相关逻辑出现 40 余处,是库的核心差异点之一;
  • 灵活选择:CSS、XPath、基于过滤条件的查找、文本搜索、正则搜索等;
  • 相似元素搜索:自动发现与已定位元素相似的其它元素;
  • MCP 服务器:内置面向 AI 的 MCP 服务器,用于 Web 抓取与数据抽取。它会在把内容交给 Claude/Cursor 等模型前先做目标内容提取,从而压缩 token 消耗;支持跨调用保持浏览器会话、页面截图与 CDP 远程浏览器控制。源码入口是 core/ai.py,文档见 ai/mcp-server.md
  • Agent Skill:仓库自带可安装的 Agent Skill,教会代码智能体按最新 API 编写 Scrapling 代码,而不是靠猜。

架构与工程化

主文档宣称的“高性能与工程可靠性”在仓库中有对应支撑:依赖声明(pyproject.toml)中解析层只依赖 lxmlcssselectorjson 等轻量库,JSON 序列化走 orjson;全量 type hints,代码库在每次变更时经 PyRight 与 MyPy 检查(pyproject.toml 中同时配置了 [tool.mypy][tool.pyright]);测试分布于 tests/ 下的 parser、fetchers、spiders、cli 等子目录。

快速上手

基础用法:三类 Fetcher 与 Session

带 Session 的 HTTP 请求(模拟 Chrome 的 TLS 指纹):

from scrapling.fetchers import Fetcher, FetcherSession

with FetcherSession(impersonate='chrome') as session:  # 使用最新版 Chrome 的 TLS 指纹
    page = session.get('https://quotes.toscrape.com/', stealthy_headers=True)
    quotes = page.css('.quote .text::text').getall()

# 或者使用一次性请求
page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()

高级隐身模式(自动处理 Cloudflare):

from scrapling.fetchers import StealthyFetcher, StealthySession

with StealthySession(headless=True, solve_cloudflare=True) as session:  # 浏览器保持打开直到结束
    page = session.fetch('https://nopecha.com/demo/cloudflare', google_search=False)
    data = page.css('#padded_content a').getall()

# 或者一次性请求风格 - 为该请求打开浏览器,完成后自动关闭
page = StealthyFetcher.fetch('https://nopecha.com/demo/cloudflare')
data = page.css('#padded_content a').getall()

完整浏览器自动化

from scrapling.fetchers import DynamicFetcher, DynamicSession

with DynamicSession(headless=True, disable_resources=False, network_idle=True) as session:
    page = session.fetch('https://quotes.toscrape.com/', load_dom=False)
    data = page.xpath('//span[@class="text"]/text()').getall()  # 也可以用 XPath

page = DynamicFetcher.fetch('https://quotes.toscrape.com/')
data = page.css('.quote .text::text').getall()

三种方式的能力取舍(静态 vs 动态 vs 隐身)在 choosing.md 中有专门讨论,分别对应 static.mddynamic.mdstealthy.md

自适应抓取的“两步走”

主文档首页示例展示了 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)    # 抓取数据并自动保存选择状态,页面改版后依然有效
products = p.css('.product', adaptive=True)     # 之后若站点结构变化,传 adaptive=True 自动重新定位

auto_save=True 保存“指纹”,之后网站改版时用 adaptive=True 恢复。这套机制的存储实现位于 storage.py,原理文档见 adaptive.md

Spider:从单个页面到完整爬虫

带翻页的并行爬虫:

from scrapling.spiders import Spider, Request, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]
    concurrent_requests = 10

    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }

        next_page = response.css('.next a')
        if next_page:
            yield response.follow(next_page[0].attrib['href'])

result = QuotesSpider().start()
print(f"Extracted {len(result.items)} quotes")
result.items.to_json("quotes.json")

response.follow()engines/toolbelt/custom.py 中实现,用于把相对链接解析为新的 Request 并入队。

一个 Spider 内混合多种会话(按 sid 路由请求):

from scrapling.spiders import Spider, Request, Response
from scrapling.fetchers import FetcherSession, AsyncStealthySession

class MultiSessionSpider(Spider):
    name = "multi"
    start_urls = ["https://example.com/"]

    def configure_sessions(self, manager):
        manager.add("fast", FetcherSession(impersonate="chrome"))
        manager.add("stealth", AsyncStealthySession(headless=True), lazy=True)

    async def parse(self, response: Response):
        for link in response.css('a::attr(href)').getall():
            # 受保护的页面路由到 stealth 会话
            if "protected" in link:
                yield Request(link, sid="stealth")
            else:
                yield Request(link, sid="fast", callback=self.parse)  # 显式 callback

Pause & Resume:以 crawldir 启动即可启用 Checkpoint:

QuotesSpider(crawldir="./crawl_data").start()

Ctrl+C 软停止时进度自动保存;下次用相同 crawldir 再启动,Spider 会从断点继续(实现见 checkpoint.py)。

模板化爬取:例如完整导出一个 Shopify 商店的商品目录(每个 variant 一条记录):

from scrapling.spiders import ShopifySpider

class MyStore(ShopifySpider):
    target_website = "example.com"

result = MyStore().start()

Spider 的架构细节、请求/响应生命周期与模板用法分别见 spiders/architecture.mdspiders/requests-responses.mdspiders/generic-templates.md

高级解析与 DOM 导航

from scrapling.fetchers import Fetcher

page = Fetcher.get('https://quotes.toscrape.com/')

# 多种选择方式
quotes = page.css('.quote')                        # CSS 选择器
quotes = page.xpath('//div[@class="quote"]')       # XPath
quotes = page.find_all('div', {'class': 'quote'})  # BeautifulSoup 风格
# 以下写法等价:
quotes = page.find_all('div', class_='quote')
quotes = page.find_all(['div'], class_='quote')
quotes = page.find_all(class_='quote')
# 按文本内容查找
quotes = page.find_by_text('quote', tag='div')

# 高级导航
quote_text = page.css('.quote')[0].css('.text::text').get()
quote_text = page.css('.quote').css('.text::text').getall()  # 选择器链式调用
first_quote = page.css('.quote')[0]
author = first_quote.next_sibling.css('.author::text')
parent_container = first_quote.parent

# 元素关联与相似性
similar_elements = first_quote.find_similar()
below_elements = first_quote.below_elements()

不加载网站时也可以直接解析本地 HTML:

from scrapling.parser import Selector

page = Selector("<html>...</html>")
# API 完全相同

选择方法与父/兄弟/子导航的完整 API 参考见 selection.mdmain_classes.md

Async 会话示例

import asyncio
from scrapling.fetchers import FetcherSession, AsyncStealthySession, AsyncDynamicSession

async with FetcherSession(http3=True) as session:  # 上下文感知,sync/async 两种模式都可用
    page1 = session.get('https://quotes.toscrape.com/')
    page2 = session.get('https://quotes.toscrape.com/', impersonate='firefox135')

# 使用 async 会话
async with AsyncStealthySession(max_pages=2) as session:
    tasks = []
    urls = ['https://example.com/page1', 'https://example.com/page2']

    for url in urls:
        task = session.fetch(url)
        tasks.append(task)

    print(session.get_pool_stats())  # 可选:浏览器标签页池状态(busy/free/error)
    results = await asyncio.gather(*tasks)
    print(session.get_pool_stats())

浏览器会话的标签页池统计 get_pool_stats()engines/_browsers/_base.py 中定义,用于观察并发浏览时各标签页的占用情况。

CLI 与交互式 Shell

Scrapling 提供完整的命令行入口,入口函数注册在 pyproject.toml[project.scripts]scraplingscrapling-mcp 两个可执行命令,均指向 cli.py)。

交互式 Web Scraping Shell(基于 IPython,内置 curl 转 Scrapling 请求、结果浏览器预览等工具):

scrapling shell

cli.py 的源码看,shell 命令支持 -c/--code 直接执行一段代码并退出,以及 -L/--loglevel 控制日志级别(默认 debug);Shell 本体实现在 core/shell.py

免代码直接抽取页面到文件(按扩展名决定输出格式:.txt 为纯文本、.md 为 Markdown 表示、.html 为 HTML 内容,默认抽取 body 内容):

scrapling extract get 'https://example.com' content.md
scrapling extract get 'https://example.com' content.txt --css-selector '#fromSkipToProducts' --impersonate 'chrome'
scrapling extract fetch 'https://example.com' content.md --css-selector '#fromSkipToProducts' --no-headless
scrapling extract stealthy-fetch 'https://nopecha.com/demo/cloudflare' captchas.html --css-selector '#padded_content a' --solve-cloudflare

命令参数在源码中可查证:extract 是一个 Click 命令组,HTTP 类命令(get/post/put/delete)共享 _common_http_options 装饰器(--impersonate 支持逗号分隔的随机选择、--stealthy-headers 默认开启、--timeout 默认 30 秒、支持 --params/--cookies/--headers/--proxy 等);浏览器类命令(fetch/stealthy-fetch)共享 _common_browser_options--headless 默认开启、--wait 毫秒级附加等待、--network-idle--disable-resources--block-ads--dns-over-https--executable-path 等)。CLI 的完整说明见 cli/overview.mdcli/extract-commands.md

性能基准

主文档给出了两类官方基准(均为 100+ 次运行取平均,方法学见 benchmarks.py):

文本提取速度(5000 个嵌套元素)

# 耗时(ms) 相对 Scrapling
1 Scrapling 1.99 1.0x
2 Parsel/Scrapy 2.06 1.035
3 Raw Lxml 2.56 1.286
4 PyQuery 23.98 ~12x
5 Selectolax 197.02 ~99x
6 MechanicalSoup 1545.15 ~776.5x
7 BS4 + Lxml 1562.1 ~785.0x
8 BS4 + html5lib 3412.73 ~1714.9x

元素相似性与文本搜索

耗时(ms) 相对 Scrapling
Scrapling 2.3 1.0x
AutoScraper 12.58 5.47x

如需复现,可直接运行仓库根目录的 benchmarks.py(测试脚本与依赖见 tests/requirements.txt)。

安装与配置

Scrapling 要求 Python ≥ 3.10(pyproject.tomlrequires-python = ">=3.10"):

pip install scrapling

重要:基础安装只包含解析引擎及其依赖(lxmlcssselectorjson 等),不含任何 Fetcher 或 CLI 依赖——此时从 scrapling.fetchersscrapling.spiders 导入会抛 ModuleNotFoundError。要使用 Fetcher/Spider,需先安装 extras 并初始化浏览器:

pip install "scrapling[fetchers]"

scrapling install           # 常规安装
scrapling install --force   # 强制重装

cli.py 源码看,scrapling install 会执行 playwright install chromiumplaywright install-deps chromium,并更新 tld 的公共后缀数据,成功后写入 .scrapling_dependencies_installed 标记文件以避免重复安装。也可以从代码内触发:

from scrapling.cli import install

install([], standalone_mode=False)          # 常规安装
install(["--force"], standalone_mode=False) # 强制重装

可选 extras

pip install "scrapling[ai]"     # MCP 服务器能力(依赖 mcp、markdownify,并隐含 fetchers)
pip install "scrapling[shell]"  # Shell 与 extract 命令(依赖 IPython、markdownify,并隐含 fetchers)
pip install "scrapling[all]"   # 全部

无论装哪个 extra,都记得随后运行 scrapling install 安装浏览器依赖。

Docker:官方镜像含全部 extras 与浏览器,从 DockerHub 或 GitHub 容器镜像仓库拉取:

docker pull pyd4vinci/scrapling
# 或
docker pull ghcr.io/d4vinci/scrapling:latest

镜像由 Dockerfile 构建并随主分支自动发布。

合规与免责声明

主文档明确:该库仅供教育与研究目的,使用者须自行遵守当地及国际数据抓取与隐私法律,作者与贡献者不对滥用负责;应始终尊重网站服务条款与 robots.txt(框架也为此提供了 robots_txt_obey 选项)。

许可、引用与致谢

  • 许可证:BSD-3-Clause(见 LICENSE);
  • 引用(若用于研究):
@misc{scrapling,
  author = {Karim Shoair},
  title = {Scrapling},
  year = {2024},
  note = {An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!}
}
登录后查看全文
热门项目推荐
相关项目推荐