Scrapling 完整教學:從單次 HTTP 請求到 AI agent 爬蟲管線

一份「讀完就能上手 + 進得了管線 + 知道資安邊界」的內部技術手冊。 目標讀者:已會 Python,正在評估 Scrapy / Playwright / BeautifulSoup 的替代方案,或要把爬蟲整進 AI agent 的工程師。


1. 為什麼選 Scrapling?

1.1 痛點背景

過去寫爬蟲常需要把三套工具縫起來:

場景慣用工具痛點
純 HTML 解析BeautifulSoup + requests慢、無 stealth、無 session、無 spider
動態網站Playwright / Selenium重、要自己包 stealth patch、無高層 API
大規模 crawlScrapy強,但無內建 stealth;要自己接 playwright-scrapy
AI agent 驅動自寫 wrappertoken 浪費(整頁 HTML 塞進 LLM)

1.2 Scrapling 的賣點

  • 統一 API:三個 Fetcher(HTTP / Dynamic / Stealthy)介面一致,換 backend 只改一個 class name。
  • Battle-tested:92% 測試覆蓋、PyRight + MyPy 全 type-check、PyPI 下載量穩定。
  • Token-efficient MCP server:AI 不再吃整頁 HTML,只拿 selector 鎖定後的元素。
  • Pause-resume 長跑 crawl:Ctrl+C 後重啟自動續跑,適合跨日 / 跨機器作業。
  • Performance:解析速度與 raw lxml 同級(2 ms vs 2.5 ms),比 BS4 快 ~780 倍。

1.3 適用 / 不適用

適用不適用
SPA / JS-render 網站抓取純 RSS / 純 static HTML(用 requests 就夠)
反爬強的目標(Cloudflare、PerimeterX)內部系統 API 抓取(直接打 REST 即可)
AI agent + 爬蟲混合工作流即時 streaming 應用(爬蟲非即時)
跨日 / 大規模 crawl 任務一次性 < 10 page 的小任務(殺雞用牛刀)

2. 安裝與環境

2.1 最小安裝(只要 parser)

1pip install scrapling

此時只有 Selector / Adaptor(lxml 包裝層),沒有 fetcher。

2.2 完整安裝(含三大 Fetcher)

1pip install "scrapling[all]"
2# 等於:scrapling[fetchers] + scrapling[ai] + scrapling[shell]
3scrapling install  # 安裝 Playwright 瀏覽器二進位

scrapling install 內部會呼叫 playwright install chromium + 套用 stealth patches。

2.3 Docker

官方有預建 image(含瀏覽器):

1docker pull pyd4vinci/scrapling:latest

2.4 推薦工作流(合規版)

依照本專案規範:

1# 用 uv 建虛擬環境
2uv venv .venv
3source .venv/bin/activate
4uv pip install "scrapling[all]"
5scrapling install

避免直接 pip 污染系統 Python。


3. 整體架構

Scrapling 的核心抽象只有四層:


flowchart TB
    subgraph User["User Code Layer"]
        A1[Fetcher / FetcherSession
HTTP requests + curl_cffi] A2[DynamicFetcher / DynamicSession
Playwright Chromium] A3[StealthyFetcher / StealthySession
Patched Chromium + anti-bot] A4[Spider
Scrapy-style crawler] A5[MCP Server
AI agent interface] end subgraph Core["Core Layer"] B1[Selector / Adaptor
lxml + CSS/XPath/BS4-style] B2[Storage
SQLite element fingerprint] B3[Translator
CSS to XPath] B4[AI Tools
token-efficient extraction] end subgraph Engine["Engine Layer"] C1[engines/static.py
HTTP impersonation] C2[engines/_browsers/chrome.py
Playwright wrapper] C3[engines/_browsers/stealth_chrome.py
stealth patches] end subgraph Infra["Infrastructure"] D1[curl_cffi
TLS / HTTP/3 fingerprint] D2[Playwright
Chromium driver] D3[lxml
HTML/XML parser] end A1 --> C1 --> D1 A2 --> C2 --> D2 A3 --> C3 --> D2 A4 --> A1 A4 --> A2 A4 --> A3 A5 --> A1 A5 --> A2 A5 --> A3 A1 -.->|parse| B1 A2 -.->|parse| B1 A3 -.->|parse| B1 B1 --> B2 B1 --> B3 A5 --> B4 B1 --> D3

關鍵理解:所有 fetcher 抓回來的 response 都會被包成同一個 Selector 物件,所以下游 parse 程式碼完全不需要知道 backend 是 HTTP / Dynamic / Stealthy。這就是「statelessness as API」的設計品味。


4. 三大 Fetcher 對照表

維度FetcherDynamicFetcherStealthyFetcher
Backendcurl_cffi (HTTP/1.1+2+3)Playwright ChromiumPatched Chromium + stealth
TLS impersonation✅ Chrome/Firefox/SafariN/A(真瀏覽器)N/A
JS rendering
Cloudflare Turnstile部分✅(內建 solver)
速度(單頁)< 200 ms~3-5 s~3-8 s
記憶體~10 MB~150 MB~200 MB
適用API、靜態頁SPA、AJAX 頁反爬強網站

4.1 最小範例(三選一)

 1from scrapling.fetchers import Fetcher, DynamicFetcher, StealthyFetcher
 2
 3# HTTP only
 4page = Fetcher.get('https://quotes.toscrape.com/', stealthy_headers=True)
 5
 6# 真瀏覽器
 7page = DynamicFetcher.fetch('https://quotes.toscrape.com/')
 8
 9# 反反爬
10page = StealthyFetcher.fetch('https://nopecha.com/demo/cloudflare', solve_cloudflare=True)
11
12# 三者下游 API 完全一致
13quotes = page.css('.quote .text::text').getall()
1from scrapling.fetchers import FetcherSession, StealthySession
2
3with FetcherSession(impersonate='chrome') as session:
4    login = session.post('https://example.com/login', data={'u': 'x', 'p': 'y'})
5    profile = session.get('https://example.com/profile')
6
7with StealthySession(headless=True, solve_cloudflare=True) as session:
8    page1 = session.fetch('https://target.com/page1')
9    page2 = session.fetch('https://target.com/page2')  # 共用同一個瀏覽器

5. Selector API:parse 層的核心

5.1 三套並存的 selection 語法

 1page = Fetcher.get('https://quotes.toscrape.com/')
 2
 3# 1) CSS(Scrapy 風)
 4quotes = page.css('.quote .text::text').getall()
 5
 6# 2) XPath
 7quotes = page.xpath('//span[@class="text"]/text()').getall()
 8
 9# 3) BS4 風
10quotes = page.find_all('span', class_='text')
11
12# 4) 文字搜尋(Scrapling 獨有)
13quote = page.find_by_text('quote', tag='div')

5.2 Adaptive selection(重點賣點)

當網站 HTML 結構變動,Scrapling 可以用「上次抓到的元素 fingerprint」找回對應元素:

 1from scrapling.fetchers import Fetcher
 2
 3# 第一次:記住元素特徵
 4page = Fetcher.get('https://example.com/article', adaptive=True)
 5title = page.css('.article-title')[0]
 6title.save('my_target')
 7
 8# 一週後網站改版,class 從 article-title 改成 post-heading
 9page2 = Fetcher.get('https://example.com/article', adaptive=True)
10title2 = page2.find_similar('my_target')  # 自動找回對應元素

實作位置:scrapling/core/storage.py(SQLite 存 fingerprint)+ scrapling/core/utils/_StorageTools(element_to_dict)。

5.3 鏈式導覽

1first = page.css('.quote')[0]
2sibling = first.next_sibling
3parent = first.parent
4similar = first.find_similar()  # 結構相似的兄弟元素

6. Spider 框架(取代 Scrapy 的場景)

6.1 最小可跑 Spider

 1from scrapling.spiders import Spider, Response
 2
 3class QuotesSpider(Spider):
 4    name = "quotes"
 5    start_urls = ["https://quotes.toscrape.com/"]
 6    concurrent_requests = 10
 7
 8    async def parse(self, response: Response):
 9        for quote in response.css('.quote'):
10            yield {
11                "text": quote.css('.text::text').get(),
12                "author": quote.css('.author::text').get(),
13            }
14        next_page = response.css('.next a')
15        if next_page:
16            yield response.follow(next_page[0].attrib['href'])
17
18result = QuotesSpider().start()
19result.items.to_json("quotes.json")

6.2 多 Session 路由(核心特色)

同一個 spider 內,把不同 URL 路由到不同 backend:

 1from scrapling.spiders import Spider, Request, Response
 2from scrapling.fetchers import FetcherSession, AsyncStealthySession
 3
 4class MultiSessionSpider(Spider):
 5    name = "multi"
 6    start_urls = ["https://example.com/"]
 7
 8    def configure_sessions(self, manager):
 9        manager.add("fast", FetcherSession(impersonate="chrome"))
10        manager.add("stealth", AsyncStealthySession(headless=True), lazy=True)
11
12    async def parse(self, response: Response):
13        for link in response.css('a::attr(href)').getall():
14            if "protected" in link:
15                yield Request(link, sid="stealth")
16            else:
17                yield Request(link, sid="fast", callback=self.parse)

設計品味點:把「該用哪種 backend」這個決策從 framework 級下放到 request 級,避免「整個 spider 為了一兩個受保護頁面全部開瀏覽器」。

6.3 Pause-Resume(長跑利器)

1QuotesSpider(crawldir="./crawl_data").start()
2# Ctrl+C → 寫 checkpoint 到 ./crawl_data/
3# 再次執行同樣指令 → 從上次斷點續跑

實作位置:scrapling/spiders/checkpoint.py,用 pickle 序列化 CheckpointData(requests=..., seen=...)

⚠️ 資安提示:checkpoint 是 pickle 格式,勿跨機器移轉 crawldir 或 chmod 700。

6.4 Streaming Mode

1spider = QuotesSpider()
2async for item in spider.stream():
3    print(item)  # 即時拿到 item,不用等全部跑完

適合接 UI / pipeline / 即時統計。


7. AI / MCP 整合

7.1 MCP Server 啟動

1scrapling mcp run
2# 或 Docker
3docker run -p 9000:9000 pyd4vinci/scrapling:latest mcp run

7.2 Claude Code 設定範例

~/.claude/mcp.json

1{
2  "mcpServers": {
3    "scrapling": {
4      "command": "scrapling",
5      "args": ["mcp", "run"]
6    }
7  }
8}

7.3 為什麼省 token

傳統做法:LLM 拿整頁 HTML(100k token) → 自己 parse → 浪費。

Scrapling MCP 做法:LLM 給 selector → server 端 parse → 只回傳元素文字(< 500 token)。

實作位置:scrapling/core/ai.py(49 KB),提供 stealthy_fetch / dynamic_fetch / bulk_* 等 tool,全部走 token-efficient 路徑。

7.4 Agent Skill ZIP

repo 內 agent-skill/Scrapling-Skill.zip 是符合 AgentSkill spec 的 skill 包,OpenClaw / Claude Code / Cursor 都能直接 install,免自己寫 prompt。


8. CLI 直接用

不寫 Python 也能用:

1# 啟動互動式 shell(IPython + Scrapling 預載)
2scrapling shell
3
4# 直接抓頁面存檔
5scrapling extract get 'https://example.com' content.md
6scrapling extract fetch 'https://spa.example.com' page.md --css-selector '#main' --no-headless
7scrapling extract stealthy-fetch 'https://protected.com' out.html --solve-cloudflare

副檔名決定輸出格式:.txt (純文字) / .md (Markdown) / .html (原始 HTML)。

實作位置:scrapling/cli.py,內部一律走對應 Fetcher。


9. 效能 benchmark(節錄官方數據)

9.1 純解析速度(5000 nested elements)

LibraryTime (ms)vs Scrapling
Scrapling2.021.0x
Parsel / Scrapy2.041.01x
Raw lxml2.541.26x
PyQuery24.17~12x
BS4 + lxml1584.31~784x
BS4 + html5lib3391.91~1679x

9.2 元素相似度搜尋

LibraryTime (ms)vs Scrapling
Scrapling2.391.0x
AutoScraper12.455.2x

數據來源:benchmarks.py(repo 根目錄,可自己跑驗證)。


10. 在我的管線中的整合位置

放在本專案的「19 Layer 知識管線」中,Scrapling 屬於輸入層補強


flowchart LR
    subgraph Input["Layer 1 / 12 / 17 輸入"]
        I1[ai-save URL]
        I2[gh-tutorial-qd GitHub repo]
        I3[v2t 影片教學]
    end

    subgraph Augment["Scrapling 補強"]
        S1[StealthyFetcher
反爬網站] S2[Spider
大量 paper / GitHub 抓取] S3[MCP Server
給 Claude Code 用] end subgraph Pipeline["19 Layer 下游"] P1[Layer 8 docling
抓回 PDF / DOCX] P2[Layer 9 paper-search
OA PDF 全文抓取] P3[Layer 10 paper-qa-lite
RAG 問答] P4[Layer 4 graphify
知識圖] end I1 -.->|fallback| S1 I2 -.->|大量 mirror| S2 I3 --> S3 S1 --> P1 S2 --> P2 P2 --> P3 P3 --> P4

10.1 三個明確切入點

切入點工具預期效益
ai-save 反爬升級StealthyFetcher目前 ai-save.sh 的 playwright fallback 改用 Scrapling,繞 Cloudflare 成功率提升
paper-search 全文補抓Spider + checkpoint過去 paper PDF 抓不到時手工補;改 Spider 跨日續跑可自動完成
Claude Code 主動爬蟲MCP server設定後,Claude 可直接「幫我看這頁有沒有 X 資訊」而不用 token-heavy 整頁 HTML

10.2 不建議的整合點

  • 不要替代 Layer 8 docling(docling 強項是 PDF / DOCX 結構化,Scrapling 是 HTML)。
  • 不要替代 Layer 1 ai-save 的 markitdown 路徑(markitdown 更快、對 simple URL 更穩)。

11. 風險、未修 bug 與決策建議

11.1 未修活躍 issue(2026-06-01 snapshot)

Issue嚴重度影響
#311 Cache Poisoning via Partial-Object Hashing🟡 中Spider 開發 cache 模式可能被污染
#313 Authenticated requests deduplication🟡 中scheduler fingerprint 沒含 headers/cookies → 認證請求可能誤合併
#295 Session-level proxy silently ignored🔴 高設定 proxy 但 fallback 直連 → IP leak
#294 init_script + user_data_dir → ERR_NAME_NOT_RESOLVED🟡 中持久化 user data 時 DNS 設定失效
#318 robots.txt parser 缺 crawl-delay🟢 低合規面強化中

建議:上線前強制設 proxy 並用 explicit assertion 驗證實際出口 IP(mitigate #295)。

11.2 機密邊界(接公司管線時)

  • Spider checkpoint 路徑 chmod 700勿放共用磁碟(pickle 反序列化攻擊面)。
  • MCP server 不要 expose 到 public network;只跑 localhost 或內部 LAN。
  • Stealth / Cloudflare bypass 使用情境:只用於有授權 / 公開資料 / 內部測試環境,不對沒授權的第三方網站使用(公司法務 / ToS 風險)。

11.3 決策建議

 1【核心判斷】
 2✅ 值得導入
 3
 4【關鍵洞察】
 5- 資料結構:三 Fetcher 統一回傳 Selector,下游 API 一致 → 換 backend 零成本
 6- 複雜度:中(裝完 Playwright + stealth patch 約 500 MB)
 7- 風險點:#295 proxy leak + pickle checkpoint + stealth 合規面
 8
 9【建議方案】
101. 先把 ai-save 的 playwright fallback 改用 StealthyFetcher(最小變動)
112. 觀察 1-2 週穩定後,把 Spider 接到 paper-search 全文補抓
123. MCP server 暫不對 Claude Code 全開放;等 #295 / #311 / #313 修完再評估
134. 用 BSD-3 + 內部分支,避免直接 fork 主線(維持與 upstream 同步彈性)

相關參考

  • 官方文件:https://scrapling.readthedocs.io
  • ROADMAP:https://github.com/D4Vinci/Scrapling/blob/main/ROADMAP.md
  • Discord:https://discord.gg/EMgGbDceNQ
  • 核心入口檔(讀原始碼從這四個開始):
    • scrapling/fetchers/__init__.py — Fetcher / DynamicFetcher / StealthyFetcher 三類入口
    • scrapling/spiders/spider.py — Spider 框架(408 行)
    • scrapling/core/ai.py — MCP server tool 定義(49 KB)
    • scrapling/parser.py — Selector / lxml 包裝層(1381 行)

內部交付物:本文件 + 對應 quarkdown 排版 HTML,存於 inbox/projects/Scrapling/quarkdown-out/