scrape-mcp
⚠️ 这是 scrape-mcp 的官方源仓库(upstream)。 若在别处看到同名/相似项目并带不同作者署名,即为转载或派生,非原作者发布。
反爬感知抓取 + 极省 Token 内容精简的 MCP Server —— 让 AI 读真实网页时,只花 1%~5% 的 token 就能拿到干净、真实、免登录的正文。
自动化分三层应对:默认 curl_cffi(伪装 TLS/JA3 + HTTP2)低成本打头阵,命中 Cloudflare/验证码/WAF 才升级 Playwright 真浏览器渲染;遇到"登录才给内容"的站,先弹窗手动登录一次、登录态落盘,之后自动带上、过期会提示重登。
⚡ 60 秒入门
方式 A:一键安装(推荐,零配置)
pip install mcp-scrape # 已发布到 PyPI 后
# 或从源码: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。
核心价值(三点)
- 极省 token —— 属性剥离 + 模板块丢弃 + 站外链接降级 + 表格转 CSV + 预算截断。实测 MDN 整页 214KB → 数百 token,压缩率约 1%。
- 自动分级反爬 —— 85% 的站只走最轻的 L1(快、并发高),拦截/JS 骨架页才升级 L2 真浏览器 + stealth 伪装,绝不暴力逐站上浏览器。
- 登录墙处理 + 如实上报 —— 判定登录/拦截时返回
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。 - 登录态持久化:
login工具手动登录并落盘,web_fetch自动带上;过期会提示重登。 - 缓存与批量:L1 明文响应按 TTL 磁盘缓存;
web_batch并发抓取一批 URL。 - 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_TIMEZONE |
Asia/Shanghai |
隐身加固时区 |
DATA_DIR |
~/.scrape_mcp |
登录态/缓存放盘目录 |
CACHE_TTL |
300 |
L1 缓存 TTL(秒),0 关闭 |
BATCH_MAX_CONCURRENCY |
4 |
web_batch 并发上限 |
BATCH_MAX_URLS |
20 |
web_batch 单批上限 |
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 即可。
必需项:请求头 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。
MCP 工具
web_fetch(url, max_tokens=4000, link_policy="internal")→ 状态 + 极省正文link_policy:internal(站内相对链接+站外降级)/all/none
web_extract(url, schema={...})→ 按字段 schema 抽取结构化 JSON(可入库)- 字段类型:
text(默认)/attr(需配attr取属性)/count/list(list_key取值)
- 字段类型:
web_batch(urls, max_tokens=3000, link_policy="internal")→ 并发抓取一批,逐 URL 返回;单条异常不影响整批login(url, timeout=180)→ 打开带界面浏览器手动登录并持久化登录态
返回为 JSON 字符串(落在 content[0].text,请解析文本,勿依赖 structured_content)。
web_extract 示例
schema='{"fields": {
"title": {"selector": "h1", "type": "text"},
"main_link":{"selector": "a", "type": "attr", "attr": "href"},
"tag_count":{"selector": ".tag", "type": "count"},
"tags": {"selector": ".tag", "type": "list", "list_key": "text"}
}}'
# → {"ok":true, "data": {"title":"…","main_link":"…","tag_count":3,"tags":["a","b","c"]}, "missing":[]}
目录结构
src/scrape_mcp
├── server.py # MCP 入口 + 工具(web_fetch/web_batch/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 响应缓存
└── extract/
├── compact.py # DOM 剪枝 → 极省 token 正文
└── schema.py # 结构化抽取(按字段 schema 出 JSON)
开发
pip install -e ".[dev]"
python -m pytest
Metadata
Release files for mcp-scrape 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| mcp_scrape-0.2.1.tar.gz | 51.0 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mcp_scrape-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 93.5 kB
Release files / mcp_scrape-0.2.1.tar.gz
| Download URL | mcp_scrape-0.2.1.tar.gz |
|---|---|
| Size | 51.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2825b563891c38a8790f45a8bd719f887229a9b887c2d7420f87e904ca78a29c
|
|
BLAKE2b-256 checksum How to use checksums |
6a1f637b23490c05df5c74e8a11591c214ad916a79ca0aff6120798e658370fa
|
| 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.2.1-py3-none-any.whl
| Download URL | mcp_scrape-0.2.1-py3-none-any.whl |
|---|---|
| Size | 42.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f9412c9601ff89373457d2f3ddf49f92cdaf73abb2b01d9debf7f20518e4f152
|
|
BLAKE2b-256 checksum How to use checksums |
fb0261401eecb66b8008fa25f08cddca322e7c42d8d6b82e2414b07f04d87028
|
| 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.2.1
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.