关于 PyScrappy
PyScrappy 是一个面向 AI Agent 的 Python 网页抓取工具包,可将网站转换为结构化、适合 LLM 使用的数据。既可作为 Python 库使用,也可作为 MCP 服务运行。其特点包括自愈式选择器和对反爬虫的应对能力。
主要功能
- 01通用抓取,返回文本、链接、图片、表格与元数据
- 02输出 Markdown、JSON 与 DataFrame 格式
- 03自愈式自适应选择器,站点改版后可重新定位元素
- 04可选 Playwright 后端,用于渲染 JavaScript 页面
- 05基于站点地图的整站抓取与并发抓取
- 06内置 22 个 MCP 工具
适用场景
- 01为 AI Agent 提供网页内容,供模型总结或分析
- 02在站点结构变化后保持长期运行的抓取任务
- 03通过命令行将网页直接导出为 Markdown 文件
MCP 相关
PyScrappy 提供 pyscrappy-mcp 服务,将其抓取器以工具形式暴露给 Claude、Cursor 等 MCP 客户端。pyscrappy chat 命令还可让本地模型通过内置 Agent 直接调用这些工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
24收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| url | string | 是 | 字符串,要抓取的页面 URL,需包含 scheme,例如 "https://example.com/products"。必填,无默认值。 |
| max_pages | integer | 否 | 整数,按“next”样式的分页继续抓取,最多抓取指定页数,例如 3。默认值为 1(仅抓取给定 URL)。 |
| render_js | boolean | 否 | 布尔值,使用无头浏览器后端渲染 JavaScript,例如 True。默认值为 False;允许的值为 True 或 False,且 True 需要安装 pyscrappy[browser] 扩展包。 |
| selectors | any | 否 | 可选字典,将输出字段名映射到用于提取特定值的 CSS 选择器,并将这些值添加到每个 data 项中,例如 {"title": "h1", "price": ".amount"}。默认值为 None(仅返回标准文本/链接/图片/表格/元数据)。 |
详细介绍
自适应 Python 网页抓取工具包(自修复、隐蔽)
+ 面向 AI Agent 的 MCP 服务
PyScrappy 是一款面向 AI 的网页抓取工具包,可将网站转换为结构化、适用于大模型的数据。可将其用作 Python 库,或将其作为 MCP 服务提供给 AI Agent 使用。
📖 文档: pyscrappy.vercel.app
主要功能
- 通用抓取器 — 输入任意 URL,即可获取结构化文本、链接、图片、表格和元数据
- 适用于大模型的输出 —
.to_markdown()可将任意结果转换为简洁的 Markdown;还支持.to_json()和.to_dataframe() - MCP 服务 — 将抓取器作为工具提供给 AI Agent 使用(Claude、Cursor、本地大模型等)
- JS 渲染 — 可选的 Playwright 后端,适用于 JavaScript 内容较多的网站
- 自定义选择器 — 传入 CSS 选择器,精准提取所需内容
- 可链式调用的
Selector— 使用 CSS/XPath、find_all、find_by_text和find_similar直接浏览 HTML(类似 Scrapy/BeautifulSoup) - 自适应(自修复)选择器 — 记住某个元素,并在网站更改标记后根据相似度重新定位,避免抓取器悄无声息地失效
- 并发抓取 —
scrape_many/scrape_all可并行执行抓取 - 站点地图爬取 — 通过
sitemap.xml枚举并抓取整个网站(支持索引和 gzip) - 代理和抓取 API 支持 — 通过代理或 ScraperAPI/ScrapeOps 访问受限网站
- TLS 指纹模拟 —
impersonate="chrome"可绕过会拦截普通客户端的反机器人过滤器(可选的curl_cffi后端) - 命令行提取 —
pyscrappy extract <url> out.md可直接将 URL 抓取到文件,无需编写代码 - 重试和速率限制 — 内置指数退避机制和按域名进行的速率限制
- 类型安全 — 完整的类型提示,带有
py.typed标记 - 20 多种内置抓取器 — Wikipedia、IMDB、股票、新闻、GitHub、Amazon/IKEA、YouTube,以及更多
安装
pip install pyscrappy
可选扩展:
# Browser support (for JS-rendered pages)
pip install 'pyscrappy[browser]'
playwright install chromium
# DataFrame support
pip install 'pyscrappy[dataframe]'
# MCP server (use PyScrappy's scrapers as AI-agent tools)
pip install 'pyscrappy[mcp]'
# Stealth (TLS-fingerprint impersonation to bypass anti-bot filters)
pip install 'pyscrappy[stealth]'
# Parquet / Excel export (ScrapeResult.to_parquet() / .to_excel())
pip install 'pyscrappy[parquet]'
pip install 'pyscrappy[excel]'
# Everything
pip install 'pyscrappy[all]'
面向 AI Agent
PyScrappy 附带一个 MCP 服务, 可将抓取器作为工具提供给 Agent 使用,因此 Agent(Claude、Cursor、OpenAI Agent、 本地大模型)可以从任意 URL 获取结构化网页数据,并直接交给模型:
AI agent ──MCP tool call──▶ PyScrappy ──fetch + extract──▶ Any website
▲ │
└────────────── clean Markdown / JSON ◀───────────────────────┘
pip install 'pyscrappy[mcp]'
claude mcp add pyscrappy pyscrappy-mcp
然后只需提出请求:“使用 pyscrappy 总结 bbc.com 上的最新头条新闻。” 完整设置说明和工具列表请参阅 MCP 服务。
本地模型(Ollama),无需 MCP 宿主
Ollama 本身无法使用 MCP,因此通常需要在中间运行一个宿主(Goose、Cline 等)。 PyScrappy 内置了一个可直接与 Ollama 通信的 Agent,无需宿主即可让本地模型 将抓取器作为工具调用:
pip install 'pyscrappy[mcp]' # needs Python 3.10+
pyscrappy chat --model qwen2.5 "what's the current AAPL quote?"
它提供与 MCP 服务相同的 22 种工具。唯一要求是模型支持工具调用
(Llama 3.1、Qwen 2.5、Mistral 等);模型能否选对工具取决于模型本身。
使用 --host 指定远程 Ollama,并传入 -v 查看每次工具调用。
MCP 服务(通过 AI Agent 使用 PyScrappy)
PyScrappy 提供可选的 Model Context Protocol 服务,因此 AI Agent(例如 Claude)可以将 PyScrappy 的抓取器作为工具调用,并 获取结构化的网页数据。
pip install 'pyscrappy[mcp]'
MCP 扩展会安装独立的 fastmcp 包,并要求 Python 3.10 或更新版本。在 Python 3.9 上,核心抓取库仍可正常使用,但 MCP 服务不可用。
这会安装 pyscrappy-mcp 命令。它默认通过 stdio 为本地 MCP 客户端提供服务;远程部署可使用 Streamable HTTP 和旧版 SSE:
pyscrappy-mcp # stdio (default)
pyscrappy-mcp --http # Streamable HTTP
pyscrappy-mcp --sse # legacy SSE
你也可以通过 python -m pyscrappy.mcp 运行 stdio 服务。
注册到 Claude Code
claude mcp add pyscrappy pyscrappy-mcp
注册到 Claude Desktop
将以下内容添加到你的 claude_desktop_config.json,然后重启应用:
{
"mcpServers": {
"pyscrappy": {
"command": "pyscrappy-mcp"
}
}
}
提示: Claude Desktop 不会继承你的 shell
PATH。如果找不到pyscrappy-mcp,请使用该命令的绝对路径(例如which pyscrappy-mcp输出的路径)。
可用工具
该服务提供 20+ 个工具。最常用的有 scrape_url(任意
URL → 文本、链接、图片、表格、元数据)、scrape_wikipedia、
scrape_stock、scrape_news 和 search_github,此外还有许多工具,涵盖图片/YouTube/LinkedIn/Hacker News/书籍搜索、天气、加密货币、货币、词典、Amazon/Newegg/IKEA/SoundCloud、IMDB 以及 Zomato/Uber Eats。
如需查看完整的实时列表,请让 Agent 调用 list_available_scrapers
工具,或在 shell 中运行:
python -c "from pyscrappy import list_scrapers; print(', '.join(sorted(list_scrapers())))"
lookup_movie 工具需要免费的 OMDb API
密钥。通过 MCP 客户端配置将其传给服务,例如在 Claude Desktop 中:
{
"mcpServers": {
"pyscrappy": {
"command": "pyscrappy-mcp",
"env": { "OMDB_API_KEY": "your-key" }
}
}
}
注册完成后,像平常一样向 Agent 提出请求即可,例如:“使用 pyscrappy 获取 bbc.co.uk 的最新头条新闻和 AAPL 股票报价。”
内置抓取器
PyScrappy 内置 24 个抓取器,其中所有无需代理即可运行的抓取器也都作为 MCP 工具提供。
其中一些包括:
GenericScraper— 自动提取任意 URL 的内容(文本、链接、图片、表格、元数据)- 数据 / 研究 —
WikipediaScraper、StockScraper(Yahoo Finance)、NewsScraper(RSS/Atom)、GitHubScraper、HackerNewsScraper,以及天气、加密货币、货币、词典、图片、LinkedIn 招聘和书籍搜索 - 电子商务 —
AmazonScraper、NeweggScraper、IKEAScraper - 社交 / 媒体 / 美食 —
YouTubeScraper、SoundCloud、Zomato、Uber Eats(也内置 Instagram / Twitter / Spotify,但这些服务受阻,需要代理)
……还有更多。如需查看完整的实时列表:
python -c "from pyscrappy import list_scrapers; print(', '.join(sorted(list_scrapers())))"
IMDBScraper(lookup_movie)是唯一需要密钥的抓取器——需要免费的
OMDb OMDB_API_KEY(如何传入密钥,请参阅上文的
MCP 配置)。
插件
PyScrappy 支持扩展:你可以添加自己的抓取器,第三方也可以将其打包为独立的 pyscrappy-<name> 包。注册后的抓取器可在所有内置抓取器可用的地方使用,包括 MCP 服务和 pyscrappy chat Agent,且无需修改 PyScrappy 核心代码。
在自己的代码中 — 使用装饰器注册:
from pyscrappy import BaseScraper, register_scraper, get_scraper
from pyscrappy.core.models import ScrapeResult, ScrapeMetadata
@register_scraper("reddit")
class RedditScraper(BaseScraper):
def scrape(self, subreddit: str, **kwargs) -> ScrapeResult:
data = self.fetch_and_parse(f"https://old.reddit.com/r/{subreddit}/.json")
# ... build a list of dicts ...
return ScrapeResult(data=[...], metadata=ScrapeMetadata(scraper="reddit"))
get_scraper("reddit")().scrape(subreddit="python")
作为可分发的包 — 在 pyproject.toml 中声明入口点,安装包后 PyScrappy 就会发现它:
[project.entry-points."pyscrappy.scrapers"]
reddit = "pyscrappy_reddit:RedditScraper"
执行 pip install pyscrappy-reddit 后,该抓取器会出现在 list_scrapers() 中,AI Agent 可以通过 scrape_with MCP 工具调用它 — 无需修改核心代码。
一等 MCP 工具(可选)。 添加 mcp_tools 映射后,你的抓取器就会成为专用的、带类型的 MCP 工具,而不只是能通过通用的 scrape_with 调用 — 它的架构会根据方法签名生成,因此 Agent 能获得规范的命名参数:
@register_scraper("reddit")
class RedditScraper(BaseScraper):
mcp_tools = {"search_reddit": "scrape"} # tool name -> method
def scrape(self, subreddit: str, sort: str = "hot") -> ScrapeResult:
...
有关完整且可复制的起始模板,请参阅插件模板;完整操作指南请参阅插件指南。
快速开始
抓取任意 URL → 整洁、适合大模型使用的 Markdown
from pyscrappy import scrape
result = scrape("https://en.wikipedia.org/wiki/Web_scraping")
print(result.to_markdown()) # feed straight to an LLM
# ...or result.to_json() / result.to_dataframe()
# Write to a file — format inferred from the extension:
result.save("out.json") # .json .csv .md .ndjson .yaml .parquet .xlsx
# (.parquet needs pyscrappy[parquet]; .xlsx needs pyscrappy[excel])
更偏好原始字段?每个结果都是一个 ScrapeResult,其中 .data 是一个字典列表:
print(result.data[0]["metadata"]["title"])
print(result.data[0]["text"]["word_count"])
自定义 CSS 选择器
from pyscrappy import GenericScraper
with GenericScraper() as gs:
result = gs.scrape(
url="https://news.ycombinator.com",
selectors={"title": ".titleline a", "score": ".score"},
)
for item in result.data:
print(item["title"], item.get("score", ""))
使用 Selector 遍历 HTML
如果你想直接遍历标记(类似 Scrapy/BeautifulSoup),而不是获取结构化字典,请使用 Selector:
from pyscrappy import Selector
page = Selector(html) # or navigate any HTML string
page.css(".title::text").getall() # CSS with ::text / ::attr(name)
page.xpath("//a/@href").getall() # XPath (elements, text(), @attr)
page.find_all("h2", class_="title") # BeautifulSoup-style search
page.find_by_text("Add to cart", tag="button") # search by text content
first = page.css(".product")[0]
first.css(".price::text").get() # chainable
first.find_similar() # sibling elements shaped like this one
css() / xpath() 会返回一个 SelectorList,其中包含 .get() / .getall() / .text()。find_similar() 会查找标签相同且类名有重叠的元素;找到一个卡片/行后,用它提取所有卡片/行会很方便。
自适应(自愈)选择器
硬编码的 CSS 选择器会在网站更改标记的那天悄然失效。 自适应选择器则能避免这种情况:首次使用时保存元素的指纹, 之后如果选择器匹配不到任何内容,就会根据结构和文本 相似度重新定位,而不是返回空结果。
from pyscrappy import Selector
# First run: match normally and remember this element under an id.
page = Selector(html_v1, url="https://shop.example.com")
price = page.css(".price", auto_save=True, adaptive_id="price").get()
# Later, after a redesign renamed ".price" — heal instead of breaking.
# `expect` is an optional contract: the relocated element must satisfy it,
# so a good structural score can't smuggle in the wrong field.
page = Selector(html_v2, url="https://shop.example.com")
result = page.css(
".price",
adaptive=True,
adaptive_id="price",
expect=lambda s: s.text().startswith("$"),
)
print(result.get(), "→ confidence:", result.adaptive_confidence)
重新定位的判断方式,以及它比简单的相似度匹配更强的地方:
- 加权信号,而非简单平均。 稳定的
id/data-*钩子的权重 远高于同级标签列表,因此弱信号无法压过强信号。 - 相对于锚点定位。 它会记住最近的稳定祖先(带 id /
data-*的 容器)及其深度,因此即使布局调整导致绝对位置变化,也能正常工作。 - 感知易变性的文本。 价格、日期和计数的权重会降低,因此 对于抓取间变化最大的字段,自愈仍然可靠。
- 置信度评分。
SelectorList.adaptive_confidence(0-100)会告知 重新定位的可信度;threshold=用于设置接受所需的最低值。 - 可选的契约强制。 传入
expect=<callable>,即可要求自愈后的 元素满足某项不变量(例如“文本看起来像价格”)。如果自愈后的结果 达到置信度阈值但不符合契约,就会被拒绝,因此仅凭结构相似度 永远不会重新定义字段的含义。
自愈会改变选择器解析到的内容,因此每次接受的自愈都会被记录。
存储会保留一份仅追加的审计日志(位于指纹存储旁的
adaptive.heal.ndjson),记录置信度、与次优匹配结果的差距,以及
自愈前后的指纹;可通过 store.heal_log() 查看——因此漂移始终
可观测,而不是被悄然吸收。若要快速概览,
store.heal_report() 会将日志汇总为每个选择器一行(自愈次数、
最新/最低/平均置信度、上次自愈时间),并按自愈次数从高到低排序
——这样漂移最多的选择器和最不稳定的重新定位结果(置信度最低)
会显示在顶部,供人工检查。
指纹会持久化到一个小型 JSON 存储中(默认位于
~/.pyscrappy/adaptive.json,也可使用 $PYSCRAPPY_HOME),并按网站
区分命名空间,因此两个网站上的相同 adaptive_id 永远不会冲突。
自适应功能完全可选:如果不设置 adaptive=True,失效的选择器仍只会
返回空结果,与以往完全相同。
针对特定网站的抓取器
每个内置抓取器都遵循相同的模式——实例化、调用 scrape(...),
读取 result.data(或 .to_dataframe() / .to_markdown()):
from pyscrappy import WikipediaScraper
with WikipediaScraper() as ws:
result = ws.scrape(query="Python (programming language)", mode="summary")
print(result.data[0]["text"])
每个抓取器都有自己的参数(Wikipedia、股票、IMDB、新闻、YouTube、 Amazon/Newegg/IKEA、Uber Eats 等——请参阅完整列表)。 有关各抓取器的参数和示例,请参阅 文档。
使用命令行
无需编写代码,即可直接抓取 URL 并保存到文件——输出格式会根据 文件扩展名推断:
pyscrappy extract https://example.com out.md # clean Markdown
pyscrappy extract https://example.com out.json # structured JSON
pyscrappy extract https://example.com out.txt # extracted page text
pyscrappy extract https://example.com out.html # raw fetched HTML
# Narrow to elements matching a CSS selector, or render JS first:
pyscrappy extract https://example.com items.txt --css-selector ".product"
pyscrappy extract https://example.com page.md --render-js
配置
from pyscrappy import ScraperConfig, GenericScraper
config = ScraperConfig(
timeout=20.0, # request timeout in seconds
max_retries=3, # retry failed requests
retry_jitter=True, # spread exponential retries to avoid lockstep traffic
rate_limit=2.0, # seconds between requests per domain
proxy="http://...", # proxy URL, or a list to rotate through
scraper_api=None, # route via a scraping-API service (see below)
headless=True, # browser runs headless
render_js="auto", # auto-detect if JS rendering is needed
cache_ttl=0, # response cache TTL in seconds (0 = disabled)
cache_dir=None, # also persist the cache to disk (survives restarts)
cache_dir_max_size=512, # max live entries kept on disk before oldest are pruned
impersonate=None, # e.g. "chrome" to spoof a browser's TLS fingerprint (see below)
)
with GenericScraper(config) as gs:
result = gs.scrape(url="https://example.com")
代理和受限网站
某些网站(例如 eBay、Instagram、Twitter/X、Spotify)会阻止直接自动化 请求。PyScrappy 提供两种绕过方式。
代理(或轮换列表)——适用于 HTTP 和浏览器后端:
from pyscrappy import ScraperConfig, AmazonScraper
# Single proxy
config = ScraperConfig(proxy="http://user:pass@host:port")
# Rotating list (one picked per request)
config = ScraperConfig(proxy=["http://p1:8080", "http://p2:8080"])
抓取 API 服务(ScraperAPI、ScrapeOps、ScrapingBee)——通过该服务 转发请求,由它为你处理代理和反机器人验证:
config = ScraperConfig(scraper_api={
"provider": "scraperapi", # or "scrapeops", "scrapingbee"
"api_key": "YOUR_KEY",
"render_js": True, # optional
})
# Now any scraper works through the service, unchanged:
with AmazonScraper(config) as scraper:
result = scraper.scrape(query="laptop")
这是使用上文标注为“需要代理”的抓取器的可靠方式。
TLS 指纹模拟——许多反机器人系统会根据普通 HTTP
客户端的 TLS/JA3 指纹将其拦截,不提供任何内容。设置 impersonate
来模拟真实浏览器的指纹,即可绕过这类拦截,无需使用无头浏览器:
from pyscrappy import ScraperConfig, GenericScraper
# needs the optional extra: pip install 'pyscrappy[stealth]'
config = ScraperConfig(impersonate="chrome") # or "chrome124", "safari", "firefox"
with GenericScraper(config) as gs:
result = gs.scrape("https://example.com")
指纹模拟适用于同步和异步路径(异步使用
curl_cffi 的 AsyncSession),因此你可以将隐匿性与高吞吐量
异步抓取结合使用。常见的重试、速率限制、缓存和 robots 处理
仍然适用。
import asyncio
from pyscrappy import scrape_async, ScraperConfig
async def main():
cfg = ScraperConfig(impersonate="chrome")
return await scrape_async("https://example.com", config=cfg)
asyncio.run(main())
并发抓取
抓取属于 I/O 密集型任务,因此同时运行多个抓取任务可以并行等待网络响应。scrape_many 使用一个抓取器处理多个输入;scrape_all 则同时运行多个不同的抓取器。两者都会保留输入顺序。
from pyscrappy import scrape_many, scrape_all, AmazonScraper, WikipediaScraper, NewsScraper
# One scraper, many queries, concurrently:
results = scrape_many(AmazonScraper, [{"query": "laptop"}, {"query": "phone"}])
# Different scrapers at once:
results = scrape_all([
lambda: WikipediaScraper().scrape(query="Python"),
lambda: NewsScraper().scrape(feed_url="https://rss.nytimes.com/services/xml/rss/nyt/World.xml"),
])
站点地图爬取
分页会跟随下一页链接;站点地图则会直接列出整个网站的 URL。GenericScraper 可以读取 /sitemap.xml(从 robots.txt 中的 Sitemap: 指令发现,或使用惯常路径),跟进 <sitemapindex> 中的子站点地图,并抓取其中列出的所有页面。
from pyscrappy import GenericScraper
with GenericScraper() as gs:
# Just enumerate the URLs:
urls = gs.sitemap_urls("https://example.com") # -> list[str]
# Or fetch + extract each, concurrently, into one result:
result = gs.scrape_sitemap("https://example.com", max_urls=100)
print(len(result.data), "pages scraped")
支持 <urlset> 叶节点和 <sitemapindex> 文件(递归一层)、gzip 压缩的站点地图(.xml.gz),并会对 URL 去重。请求会经过常规的速率限制、缓存、代理和隐身处理机制,批量抓取会复用 scrape_all。max_urls 用于限制爬取数量(站点地图可能列出数万个 URL,因此 scrape_sitemap 必须设置此参数)。
响应缓存
将 cache_ttl 设置为正数秒数,即可缓存成功的 GET 响应。在 TTL 时间内,对相同 URL(和查询参数)的重复请求会从缓存中提供,从而跳过网络请求和速率限制器。缓存默认禁用(cache_ttl=0)。
from pyscrappy import WikipediaScraper
from pyscrappy import ScraperConfig
config = ScraperConfig(cache_ttl=300) # cache for 5 minutes
with WikipediaScraper(config) as ws:
ws.scrape(query="Python") # fetched over the network
ws.scrape(query="Python") # served from cache
缓存存储在内存中,并由同一进程中的所有抓取器实例共享(因此也能加速通过 MCP 服务进行的重复调用),进程退出时会清空。调用 HttpClient.clear_cache() 可手动清空缓存。
缓存采用 LRU 限制大小:最多保留 cache_max_size 个有效条目(默认值为 512);达到上限后,会淘汰最近最少使用的条目。因此,长期运行的进程(例如 MCP 服务)即使抓取许多不同的 URL,缓存也会保持在限定范围内,而不会一直增长到进程重启。可按需调高或调低上限:
config = ScraperConfig(cache_ttl=300, cache_max_size=2000)
持久化(磁盘)缓存。 设置 cache_dir 还可将响应持久化到磁盘,使缓存命中在进程重启和不同运行之间仍然有效——这对重新运行抓取任务或 CLI 作业而无需重新获取内容很有用。内存缓存仍会作为前置层提供加速;命中磁盘缓存后,条目会重新载入内存。
config = ScraperConfig(cache_ttl=3600, cache_dir="~/.cache/pyscrappy")
磁盘缓存也有大小限制:每次写入时都会清除过期条目,并将条目数量裁剪到 cache_dir_max_size(默认值为 512)以内,因此 cache_dir 不会因每个不同 URL 都生成一个文件而无限增长。
clear_cache() 会清空内存缓存;磁盘缓存会按设计保留——删除其 cache_dir 即可清除。
可观测性钩子
对于长时间运行的爬取任务,可传入轻量级回调实时监控请求(进度条、指标),而无需启用日志记录:
config = ScraperConfig(
on_request=lambda url: print("GET", url), # before a network fetch
on_retry=lambda url, attempt, delay, err: print("retry", attempt, url),
on_cache_hit=lambda url: print("cached", url), # served from cache
)
on_request(url)会在获取 URL 前触发一次(缓存命中时不会触发)。on_retry(url, attempt, delay, error)会在每次退避等待前触发。on_cache_hit(url)会在请求由缓存提供时触发。
这三个回调都尽力执行:如果回调抛出异常,会以 debug 级别记录,且不会中断抓取。它们在同步和异步路径中都会触发。
依赖项
必需: httpx、beautifulsoup4、lxml
可选: playwright(JS 渲染)、pandas(DataFrame)、fastmcp(MCP 服务,Python 3.10+)
许可证
贡献
欢迎所有贡献。请参阅 Issues。
此软件包仅用于教育和研究目的。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。