内容
<div align="center">
<pre>
███████╗███╗ ███╗██████╗ ███████╗██████╗
██╔════╝████╗ ████║██╔══██╗██╔════╝██╔══██╗
█████╗ ██╔████╔██║██████╔╝█████╗ ██████╔╝
██╔══╝ ██║╚██╔╝██║██╔══██╗██╔══╝ ██╔══██╗
███████╗██║ ╚═╝ ██║██████╔╝███████╗██║ ██║
╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚═╝ ╚═╝
</pre>
**开源、轻量级无头浏览器,适用于 AI 代理。**
[](https://pypi.org/project/ember-browser/)
[](https://pypi.org/project/ember-browser/)
[](LICENSE)
```bash
pip install ember-browser
```
*无需 Docker,无需 API 密钥即可开始。*
</div>

---
## 为什么选择 ember
大多数用于代理的网络工具都附带 Chromium(约 281 MB)或需要 Docker 才能开始使用。我们需要一种代理可以在 VPS、笔记本电脑或 Raspberry Pi 上使用,而无需考虑这些问题。
ember 运行内存约为 17 MB。它可以判断一个页面是否需要浏览器 - 您只需传递一个 URL。
| | ember | Crawl4AI | Firecrawl OSS | Playwright |
|--------------------------|------------------------|------------------------|------------------------|------------------------|
| 设置 | `pip install` | `pip install` | Docker + Redis + Node | `pip` + 浏览器安装 |
| 包大小 | ~54 MB | ~200–350 MB | 仅限薄客户端 | ~47 MB |
| 浏览器二进制文件 | Lightpanda ~12 MB | Chromium ~281 MB | Chromium ~281 MB | Chromium ~281 MB |
| 是否需要 Docker | 否 | 否 | 是 | 否 |
| 是否需要 API 密钥 | 否 | 否 | 否 | 否 |
| MCP 服务器 | 是 | 否 | 是 | 是 |
| 搜索内置 | 是 | 否 | 是 | 否 |
| 零基础设施自托管 | 是 | 是 | 否 | 是 |
---
## 快速开始
```bash
pip install ember-browser
ember version # 验证安装
ember # 启动交互式会话
ember url https://example.com # 或运行一次性命令
ember serve # 启动 REST API
```
---
## 命令行界面
### 交互式会话
`ember` 不带参数即可打开持久会话。命令和保存指南在启动时显示 - 无需首先输入 `help`。
<pre>
███████╗███╗ ███╗██████╗ ███████╗██████╗
██╔════╝████╗ ████║██╔══██╗██╔════╝██╔══██╗
█████╗ ██╔████╔██║██████╔╝█████╗ ██████╔╝
██╔══╝ ██║╚██╔╝██║██╔══██╗██╔══╝ ██╔══██╗
███████╗██║ ╚═╝ ██║██████╔╝███████╗██║ ██║
╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚═╝ ╚═╝
v0.1.0 适用于 AI 代理的轻量级无头浏览器
url <url> 将页面抓取为 Markdown
search <query> 网络搜索
crawl <url> 抓取整个网站
map <url> 发现站点上的所有 URL
interact <url> 使用自然语言控制浏览器
extract <url> 使用 LLM 拉取结构化数据
batch <urls.txt> 并发抓取多个 URL
─── 保存结果 ───────────────────────────────────────────
单个结果 url example.com -o page.md
所有结果 output ./research/ 然后自动保存所有结果
上一个结果 save page.md 在任何命令后
ember › url andausman.com
ember › save page.md
ember › output ./research/ # 从这里开始自动保存所有结果
ember/research › search "python asyncio" -n 10
ember/research › crawl docs.example.com
ember/research › output clear # 停止自动保存
ember › quit
</pre>
### 一次性命令
每个命令也可以独立工作:
```bash
ember url https://example.com # 抓取页面
ember search "AI 代理 python" -n 10 # 网络搜索
ember crawl https://docs.example.com --max-pages 20 # 抓取站点
ember map https://example.com # 发现所有 URL
ember interact https://amazon.com \
--prompt "找到一个价格低于 $100 的机械键盘"
ember extract https://example.com/pricing \
--prompt "列出所有计划和价格为 JSON"
```
### 保存结果
所有命令都接受 `-o` 以保存运行结果:
```bash
ember url https://example.com -o page.md
ember search "python" -o results.json
ember crawl https://docs.example.com -o ./pages/ # 每个页面一个 .md
ember map https://example.com -o urls.txt
ember extract https://example.com -o data.json
```
设置默认保存目录,以便您无需始终使用 `-o`:
```bash
ember config --save-dir ./research/ # 持久化跨会话
ember config # 显示当前设置
ember config --save-dir "" # 清除它
```
或为当前 shell 使用环境变量:
```bash
EMBER_SAVE_DIR=./out ember url https://example.com
```
在一个会话中,有三种保存方式:
```
ember › url example.com -o page.md # 只保存此运行结果
ember › save page.md # 保存上一个结果
ember › output ./research/ # 从现在开始自动保存所有结果
```
### 异步批量抓取
```bash
# urls.txt — 每行一个 URL,# = 注释
ember batch urls.txt # 默认 5 个并发
ember batch urls.txt -c 20 -o ./pages/ # 20 个并发,保存到目录
```
---
## Python API
```python
from emb.scrape import scrape_url, scrape_markdown
from emb.search import search
from emb.crawl import crawl
from emb.map import map_url
# 抓取页面 → ScrapeResult
result = scrape_url("https://example.com")
print(result.markdown) # 整个页面内容为 Markdown
print(result.title) # 页面标题
print(result.success) # True / False
# 仅限 Markdown 文本
md = scrape_markdown("https://example.com")
# 抓取站点
result = crawl("https://docs.example.com", max_pages=20, max_depth=3)
for page in result.pages:
print(page.url, len(page.markdown))
# 发现 URL
result = map_url("https://example.com", max_links=100)
print(result.links) # list[str]
# 搜索网络
results = search("python asyncio tutorial", limit=5)
for r in results:
print(r.title, r.url)
# 使用自然语言进行浏览器交互
from emb.interact import interact
result = interact("https://example.com", prompt="点击登录按钮")
print(result.content) # 代理执行的操作 / 看到的内容
# 基于 LLM 的结构化提取
from emb.agent import extract
data = extract("https://example.com/pricing", prompt="列出所有计划和价格")
print(data) # dict
```
### 异步
```python
import asyncio
from emb.scrape import scrape_url_async
async def main():
results = await asyncio.gather(
scrape_url_async("https://example.com"),
scrape_url_async("https://httpbin.org/get"),
)
for r in results:
print(r.url, r.success)
asyncio.run(main())
```
---
## REST API
```bash
ember serve # http://127.0.0.1:51251
ember serve --port 8080 # 自定义端口
EMBER_API_KEY=your-secret ember serve # 需要身份验证
```
```bash
curl -X POST http://localhost:51251/scrape \
-H "Content-Type: application/json" \
-H "X-API-Key: your-secret" \
-d '{"url": "https://example.com"}'
curl -X POST http://localhost:51251/search \
-H "Content-Type: application/json" \
-d '{"query": "AI 代理", "limit": 5}'
curl -X POST http://localhost:51251/crawl \
-H "Content-Type: application/json" \
-d '{"url": "https://docs.example.com", "max_pages": 10}'
```
端点:`/scrape` `/search` `/crawl` `/map` `/interact` `/extract` `/agent` `/health`
---
## MCP
添加到您的 Hermes 配置、OpenClaw 配置、Mercury 配置或任何与 MCP 兼容的主机:
```json
{
"mcpServers": {
"ember": {
"command": "ember",
"args": ["mcp"]
}
}
}
```
与 Hermes、OpenClaw、Mercury 和任何与 MCP 兼容的主机兼容。
可用工具:`scrape`、`search_web`、`crawl_site`、`map_site`、`batch_scrape`、`interact_page`、`extract_data`。
连接后,您的代理可以直接在对话中使用 ember 工具:
```
用户:总结 Hacker News 上的最新帖子
代理:[调用 scrape("https://news.ycombinator.com")]
→ 返回带有标题、分数、链接的完整页面 Markdown
代理:以下是 Hacker News 今日的热门话题:...
```
```
用户:找到 5 篇关于 AI 代理的文章并抓取每一篇
代理:[调用 search_web("AI 代理 2025", limit=5)]
→ 返回 {title, url, description} 列表
代理:[调用 batch_scrape(["url1", "url2", ...])]
→ 返回每个页面的 Markdown
代理:以下是 5 篇文章的摘要:...
```
---
## 工作原理
并非每个页面都需要浏览器。ember 知道其中的区别。
**第一层 — trafilatura** 处理约 89% 的网络:博客、新闻、文档、文档站点、GitHub。纯 HTTP,无浏览器进程,无内存开销。
**第二层 — Lightpanda** 处理 JavaScript 密集型页面、SPA 和交互式内容。它是用 Zig 编写的真正的浏览器引擎,专为机器而非人类设计 - 总共 20 MB。ember 在首次使用时自动下载并缓存它,并且仅在第一层产生的内容很少时才使用它。
大多数请求从未到达浏览器。
### 内存占用
| 状态 | RAM |
|------------------------|---------|
| 空闲 | ~17 MB |
| 抓取静态页面 | ~20 MB |
| 运行浏览器 | ~140 MB |
Firecrawl 需要 4–8 GB 的 Docker 内存。Crawl4AI 导入时为 171 MB,然后再抓取任何内容。ember 可以在您的代理已经运行的地方运行。
---
## 环境变量
| 变量 | 默认值 | 描述 |
|---------------------------|--------------------------------|-------------|
| `EMBER_SAVE_DIR` | _(无)_ | 默认保存结果的目录。覆盖 `ember config --save-dir` 以适用于当前 shell。 |
| `EMBER_API_KEY` | _(无)_ | 在 REST 服务器上启用 API 密钥身份验证(`X-API-Key` 头)。 |
| `EMBER_PORT` | `51251` | `ember serve` 的默认端口。被 `--port` 标志覆盖。 |
| `EMBER_INTERACT_PROVIDER` | `openai` | `interact` 的 LLM 提供者(`openai`、`anthropic`、`ollama` 等)。 |
| `EMBER_LLM_API_KEY` | _(无)_ | LLM 驱动的提取的 API 密钥。 |
| `EMBER_LLM_BASE_URL` | `https://api.openai.com/v1` | 提取的 LLM API 端点。 |
| `EMBER_LLM_MODEL` | `gpt-4o-mini` | `extract` 使用的模型。 |
| `EMBER_LIGHTPANDA_PATH` | _(自动)_ | 自定义 Lightpanda 二进制文件的路径。如果设置,则跳过自动下载。 |
---
## 许可证
[MIT](LICENSE) — 永久开源。