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 |
| 大規模 crawl | Scrapy | 強,但無內建 stealth;要自己接 playwright-scrapy |
| AI agent 驅動 | 自寫 wrapper | token 浪費(整頁 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 對照表
| 維度 | Fetcher | DynamicFetcher | StealthyFetcher |
|---|---|---|---|
| Backend | curl_cffi (HTTP/1.1+2+3) | Playwright Chromium | Patched Chromium + stealth |
| TLS impersonation | ✅ Chrome/Firefox/Safari | N/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()
4.2 Session 版(多 request 共享 cookie / state)
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)
| Library | Time (ms) | vs Scrapling |
|---|---|---|
| Scrapling | 2.02 | 1.0x |
| Parsel / Scrapy | 2.04 | 1.01x |
| Raw lxml | 2.54 | 1.26x |
| PyQuery | 24.17 | ~12x |
| BS4 + lxml | 1584.31 | ~784x |
| BS4 + html5lib | 3391.91 | ~1679x |
9.2 元素相似度搜尋
| Library | Time (ms) | vs Scrapling |
|---|---|---|
| Scrapling | 2.39 | 1.0x |
| AutoScraper | 12.45 | 5.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/。
Comments