Skip to main content

scrape-mcp

⚠️ 这是 scrape-mcp 的官方源仓库(upstream)。 若在别处看到同名/相似项目并带不同作者署名,即为转载或派生,非原作者发布。

反爬感知抓取 + 极省 Token 内容精简的 MCP Server —— 让 AI 读真实网页时,只花 1%~5% 的 token 就能拿到干净、真实、免登录的正文。

自动化分三层应对:默认 curl_cffi(伪装 TLS/JA3 + HTTP2)低成本打头阵,命中 Cloudflare/验证码/WAF 才升级 Playwright 真浏览器渲染;遇到"登录才给内容"的站,先弹窗手动登录一次、登录态落盘,之后自动带上、过期会提示重登。

License: MIT PyPI Python Release CI


⚡ 60 秒入门

方式 A:一键安装(推荐,零配置)

pip install mcp-scrape
# 或从源码:cd scrape-mcp && pip install -e .

然后本机任意目录即可:

scrape-mcp --version          # 确认装好(应输出 0.x)
claude                        # 在支持 MCP 的客户端里把它当服务接入

不再需要 clone、手动设 PYTHONPATH 或 python -m;scrape-mcp 命令在任意目录可用, 默认 stdio 直接被 MCP 客户端接管。想用 HTTP 直连(Postman/curl),跑 scrape-mcp --transport streamable-http --port 8000。

方式 B:一键演示(拉源仓库跑 web_fetch + web_extract,看省 token 效果)

git clone https://github.com/guanyuyan/scrape-mcp.git
cd scrape-mcp
python -m venv .venv && .venv\Scripts\pip install -e .
.venv\Scripts\python scripts\demo.py

预计输出(对不同站点自动选 L1/L2 分级,给出省 token 压缩比):

=== 文档站 | https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS
  ok=True tier=l1 status=200 html=260128B → tokens=3730 (约 5.7% 压缩)
  标题: 跨源资源共享(CORS) - HTTP | MDN
  ok=True tier=l1 data={"heading": "跨源资源共享(CORS)", "h2_count": 10, "links": 665}

第 2 步:作为 MCP 客户端接入(Claude / Cursor 等,命令指向已安装的 scrape-mcp)

scrape-mcp            # 已安装时;或 python -m scrape_mcp.server

在客户端里调用 web_fetch(url=...) 即可拿到极省正文。

MDN 整页约 260KB,这里只花几千 token 就拿到干净正文;拦截/登录页会自动升级或如实上报,不会把验证码当正文。


功能说明

它解决什么:模型读网页不是在读正文,而是在读整棵 DOM(脚本、导航、版权、链接一应尽收),又贵又脏。这个工具把页面剪成"只有正文"再喂给 AI。

核心价值(三点)

  1. 极省 token —— 属性剥离 + 模板块丢弃 + 站外链接降级 + 表格转 CSV + 预算截断。实测 MDN 整页 214KB → 数百 token,压缩率约 1%。
  2. 自动分级反爬 —— 85% 的站只走最轻的 L1(快、并发高),拦截/JS 骨架页才升级 L2 真浏览器 + stealth 伪装,绝不暴力逐站上浏览器。
  3. 登录墙处理 + 如实上报 —— 判定登录/拦截时返回 login_required/blocked,引导登录而非硬撞,从不让模型把验证码当正文。

怎么用(一行)

web_fetch(url="https://xxx/article/1") → JSON:{ok, content(极省正文), token_estimate, tier, blocked?, login_required?, cached?}

覆盖的站点类型:文章页 / 文档站 / 门户与列表页 / 需要 JS 渲染的 SPA / 需要登录才给正文的站(如知乎)。

真实站点实测(一键 scripts/demo.py 可复现):

站点 类型 分级 原始 抓到正文 说明
MDN CORS 文档 文档站 L1 260KB ~3.7k token(约 5.7%) 纯静态,最短路径直达
腾讯新闻首页 列表/门户 L2 338KB ~1.4k token(约 1.6%) 动态页升级浏览器渲染
极客邦首页 SPA/动态 L2 12KB ~1.4k token JS 骨架页,需渲染才有正文

形态:本地 MCP Server(stdio/HTTP 均可),隐私可控;支持单页 web_fetch、批量 web_batch、结构化抽取 web_extract、登录持久化 login,缓存默认开启。


特性

  • 分级抓取:L1 curl_cffi → L2 Playwright,拦截才升级,不误伤正常页面。
  • 内容密度选根:从 article/main/div 中挑出"恰好装住正文的最紧容器",避开导航/侧栏。
  • compact 精简:属性剥离、模板块丢弃、站外链接降级、表格转 CSV、token 预算截断, 压缩率可达 1~20% 数量级(如 MDN 214KB → 数百 token)。
  • 拦截如实上报:不把挑战页/空壳页当正文喂给模型,返回 blocked/block_reason。
  • 稳定错误码:error_code(timeout/dns/tls/connection/blocked/login_required/http_4xx…),调用方可程序化决策。
  • 登录态持久化:login 工具手动登录并落盘,web_fetch 自动带上;过期会提示重登。
  • 缓存与批量:L1 明文响应按 TTL 磁盘缓存;web_batch 并发抓取一批 URL。
  • 轻量爬取:web_crawl 按 depth/limit 发现站内链接并逐页抓取,静态资源自动跳过。
  • 输出格式可选:format=markdown|text|json,正文可按段落数组直接入库。
  • 同域并发闸门:同一站点默认最多 2 个并发请求,跨站仍可并行,避免批量抓取时把单站打穿。
  • Stealth 加固:Wipe webdriver、UA 数据、Canvas/WebGL 确定性指纹噪声、时区对齐。

安装

# L2 渲染所需浏览器(国内可用镜像)
$env:PLAYWRIGHT_DOWNLOAD_HOST="https://cdn.npmmirror.com/binaries/playwright"
pip install "playwright>=1.49"
playwright install chromium

# 或复用系统浏览器,无需下载
$env:SCRAPE_MCP_L2_CHANNEL="chrome"   # 或 msedge

启动(MCP,stdio)

scrape-mcp                          # 默认 stdio,被 MCP 客户端接管
scrape-mcp --transport streamable-http --port 8000   # 切 HTTP 直连
scrape-mcp --version / --help       # 版本 / 用法

不传参默认 stdio。传 --transport/--port 由 CLI 显式启动,优先级高于 .env/环境变量。

环境变量(前缀 SCRAPE_MCP_)

全部配置可用环境变量(SCRAPE_MCP_ 前缀)设置,也可集中放到项目根目录 .env 文件里。

# 项目根目录执行
cp .env.example .env    # 生成配置模板
# 编辑 .env 后无需改代码,直接启动即可

优先级:实际进程环境变量 > .env > 默认值。.env 被 gitignore,不入库;.env.example 是随仓库提交的模板。

变量 默认 说明
IMPERSONATE chrome curl_cffi 指纹模板
REQUEST_TIMEOUT 20 L1 超时(秒)
PROXY — 代理,L1/L2 共用
L2_ENABLED true 是否启用 Playwright 升级链
L2_CHANNEL — 关联浏览器:空=自带 Chromium,chrome/msedge=系统
L2_SETTLE_TIMEOUT 8 挑战页等待窗口(秒)
L2_SCROLL_STEPS 5 L2 滚动步数(触发懒加载)
L2_SCROLL_DELAY_MS 400 L2 每步滚动间隔(毫秒)
L2_TIMEZONE Asia/Shanghai 隐身加固时区
DATA_DIR ~/.scrape_mcp 登录态/缓存放盘目录
CACHE_TTL 300 L1 缓存 TTL(秒),0 关闭
RETRY_TIMES 2 网络异常/5xx 重试次数(429/403 不重试)
RETRY_BACKOFF 0.5 重试退避基数(秒,指数增长)
BATCH_MAX_CONCURRENCY 4 web_batch 并发上限
BATCH_MAX_URLS 20 web_batch 单批上限
HOST_MAX_CONCURRENCY 2 同一主机的并发上限(web_batch/web_crawl 共用)
CRAWL_MAX_PAGES 20 web_crawl 单次最多抓取页数硬上限
RESPECT_ROBOTS true 默认遵循目标站 robots.txt;false 忽略(仅建议自用合规场景关闭)
ALLOWED_HOSTS — 主机白名单(逗号分隔);非空时仅允许名单内主机
DENIED_HOSTS — 主机黑名单(逗号分隔),优先于白名单
MAX_QPS 10 全网抓取限流(每秒请求数);0 不限速

HTTP 模式(Postman / curl 直连)

默认 stdio,改环境变量即可切到 HTTP,无需改代码:

$env:SCRAPE_MCP_TRANSPORT="streamable-http"
$env:SCRAPE_MCP_HTTP_PORT="8000"
python -m scrape_mcp.server

以 json_response=1(默认)启动,请求/响应都是普通 JSON(非事件流)。stateless 模式无需先 initialize,直接发 tools/call 即可。 健康检查:GET /healthz 返回版本与关键开关,可用于容器探针/网关巡检。

必需项:请求头 MCP-Method、Mcp-Name;body 内 params 需带 _meta(protocolVersion + clientCapabilities)。完整示例见下。

接入 MCP 客户端(Claude / Cursor 等)

先 pip install mcp-scrape(或用项目 .venv 跑 pip install -e .),使 scrape-mcp 命令全局可用;然后按标准 MCP 方式接入。

以 Claude Desktop 为例(claude_desktop_config.json):

{
  "mcpServers": {
    "scrape-mcp": {
      "command": "scrape-mcp"
    }
  }
}
  • 用 command: "scrape-mcp"(已全局安装),免去 PYTHONPATH 与系统解释器导致的 ModuleNotFoundError。
  • 若复用系统浏览器(免下载):设环境变量 SCRAPE_MCP_L2_CHANNEL 为 chrome 或 msedge。
  • 配对成功后重启客户端,即可在会话里直接调用 web_fetch / web_extract / web_batch / web_crawl。

MCP 工具

  • web_fetch(url, max_tokens=4000, link_policy="internal", format="markdown", ...) → 状态 + 极省正文
    • link_policy: internal(站内相对链接+站外降级)/ all / none
    • format: markdown(默认,保留标题/列表/链接)/ text(剥掉标记的纯文本)/ json(content 为段落数组)
    • 抓取参数:headers / cookies(自定义请求,不走共享缓存)、timeout、bypass_cache
    • 渲染参数(仅 L2 生效):wait_for(等 CSS 选择器)、scroll(滚动触发懒加载)、click(点"加载更多")
  • web_extract(url, schema={...}, ...) → 按字段 schema 抽取结构化 JSON(可入库)
    • 字段类型:text(默认)/ html / attr(需配 attr)/ count / list / object
    • 嵌套:list 配 fields 返回对象数组,object 在匹配节点内部继续抽取
    • 后处理:regex + group(正则提取,未命中回落 default)、abs_url(相对链接转绝对)、strip
    • 抓取/渲染参数与 web_fetch 相同(不含 link_policy/format)
  • web_batch(urls, max_tokens=3000, link_policy="internal", format="markdown", ...) → 并发抓取一批,逐 URL 返回;单条异常不影响整批
    • 支持 headers / cookies / timeout / bypass_cache(对该批所有 URL 生效)
  • web_crawl(url, depth=1, limit=10, same_host=True, max_tokens=2000, ...) → 从起始页按层发现站内链接并逐页抓取
    • depth:跳转层数,0 只抓起始页,最大 3;limit:总页数上限(受 CRAWL_MAX_PAGES 约束)
    • 单页失败只影响该页;图片/压缩包等静态资源链接自动跳过
  • login(url, timeout=180) → 打开带界面浏览器手动登录并持久化登录态

返回为 JSON 字符串(落在 content[0].text,请解析文本,勿依赖 structured_content)。 失败时带稳定 error_code;传输失败/5xx 会自动指数退避重试,attempts 为实际尝试次数;L2 交互未命中(如选择器不存在)只在 notes 中提示,不判失败。

web_extract 示例

schema='{"fields": {
  "title":     {"selector": "h1"},
  "price":     {"selector": ".price", "regex": "¥([\\d.]+)", "group": 1},
  "main_link": {"selector": "a", "type": "attr", "attr": "href", "abs_url": true},
  "tag_count": {"selector": ".tag", "type": "count"},
  "tags":      {"selector": ".tag", "type": "list", "list_key": "text"},
  "items":     {"selector": ".item", "type": "list", "fields": {
    "name": {"selector": ".name"},
    "url":  {"selector": "a", "type": "attr", "attr": "href", "abs_url": true}
  }}
}}'
# → {"ok":true, "data": {"title":"…","price":"299.00","main_link":"https://…",
#    "tag_count":3,"tags":["a","b","c"],"items":[{"name":"…","url":"https://…"}]}, "missing":[]}

Docker

# 仅 L1(镜像小,覆盖大多数页面)
docker build -t scrape-mcp .

# 带 L2 真浏览器(Cloudflare/验证码/SPA)
docker build --build-arg INSTALL_BROWSER=1 -t scrape-mcp:l2 .

docker run -p 8002:8002 scrape-mcp
curl http://127.0.0.1:8002/healthz     # {"ok":true,"version":"…"}

目录结构

src/scrape_mcp
├── server.py          # MCP 入口 + 工具(web_fetch/web_extract/web_batch/web_crawl/login)
├── config.py          # 环境变量配置
├── tokenizer.py       # tiktoken 计数 + 预算截断
├── core/
│   ├── http_client.py # L1 curl_cffi + 磁盘缓存
│   ├── fetcher.py     # 分级调度(L1→L2),对工具层返回 FetchOutcome
│   ├── detector.py    # 拦截/骨架页判定
│   ├── browser.py     # L2 Playwright + stealth
│   ├── session.py     # 登录态持久化
│   ├── cache.py       # HTTP 响应缓存
│   ├── errors.py      # 统一错误码
│   └── hostlimit.py   # 同域并发闸门
└── extract/
    ├── compact.py     # DOM 剪枝 → 极省 token 正文
    ├── schema.py      # 结构化抽取(按字段 schema 出 JSON)
    ├── links.py       # 链接发现(web_crawl 用)
    └── render.py      # markdown → 纯文本 / 分块

开发

pip install -e ".[dev]"
python -m pytest

Metadata

Release files for mcp-scrape 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mcp-scrape 0.3.0
File Size Uploaded Provenance
mcp_scrape-0.3.0.tar.gz 67.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for mcp-scrape 0.3.0
File Interpreter ABI Platform
mcp_scrape-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 121.8 kB

Release files / mcp_scrape-0.3.0.tar.gz

Download URL mcp_scrape-0.3.0.tar.gz
Size 67.9 kB
Tags Source
SHA-256 checksum
How to use checksums
fdeda58bbc88af4292aed4d3a7a411315639fc2f9b3c9f72cf9d35530798a960
BLAKE2b-256 checksum
How to use checksums
df0ef04ec78dfd98831391dcebe75844178c965145c299e41d33c8702033562a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.2

Release files / mcp_scrape-0.3.0-py3-none-any.whl

Download URL mcp_scrape-0.3.0-py3-none-any.whl
Size 53.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b23397667b528cae9fa58a5159d90e3c685fb70d483d46d04ea8a9536b03d6f7
BLAKE2b-256 checksum
How to use checksums
b1638f562edf76750cff2fe768520e5d0e43c582dd692f1cd269c5fa50b1d852
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.2

Security for mcp-scrape 0.3.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page