在 GitHub 已获得 84 个星标,且数量仍在增加。Yozh Crawler + Scraper 是一款免费、开源且公开开发的工具——如果它能成为您技术栈中的一员,请给我们点个星标
CyberYozh Data / Yozh 爬行器
软件 · Yozh Crawler

只需输入一个种子URL,整个网站的内容便能流式传输出来

Yozh Crawler 从单个 URL 开始爬取网站,并通过 SSE 流式传输发现的每一页。它负责处理爬取过程中的难点——边界检测、去重、范围控制、礼貌请求和重试——而每个页面的抓取都会经过 Yozh Scraper 处理。没有 Playwright 的功能重复,没有 SaaS,运行于 :8001.

$curl -N :8001/api/v1/crawl -d '{"seed_url":"https://site.com", "scope":{"mode":"same-domain","max_depth":2,"max_pages":500}}'

爬取

Yozh Crawler 从单个种子 URL 开始爬取网站,并通过 SSE 流式传输发现的每一页。它负责发现过程——边界探索、去重、范围控制、链接提取、重试和礼貌请求——而每个页面的抓取任务则通过 HTTP 委托给 Yozh Scraper 处理。 整个系统仅需维护一套 Playwright 技术栈,且所有抓取器功能(代理、隐身模式、会话管理、提取规则)同样适用于被爬取的页面。

  • 范围谓词same-domain / subdomains / all / regex,包含“包含”与“排除”模式以及硬 max_depth / max_pages 上限。
  • 指纹去重——先对 URL 进行规范化处理,然后进行哈希(SHA1)运算,这样,顺序不同的查询和带尾斜杠的变体都会被归为一次访问。
  • 按域轮询机制——一个运行缓慢或体积庞大的主机不会导致其他主机无法获得工作进程。
  • 自适应速率限制器——一个跨作业共享的、按域划分的全局令牌桶(带抖动);一个 429 在冷却窗口期间将 RPS 减半。
  • 会话健康状况——Crawlee式评分法: 401/403/429 终止会话时,错误会提高其评分,成功则降低评分;当评分≥3或使用次数≥50时进行轮换。
  • SSE 流式处理——每个任务都会发出 stats, page, page_error,以及终端 done / cancelled 事件。在检测结果出现时立即采取行动。
基础网址http://localhost:8001
OpenAPI 文档http://localhost:8001/docs
MCP 端点http://localhost:8001/mcp
辅助服务。爬虫会将每次抓取任务委托给 Yozh Scraper,因此请同时启动这两个服务——将 Yozh Scraper 部署在 :8000 ,爬虫则运行在 :8001.

快速开始

爬虫通过配置连接到根节点 docker-compose.yml 并随抓取程序一同启动:

bash
docker compose up --build
# scraper  → http://localhost:8000
# crawler  → http://localhost:8001

或者在不使用 Docker 的情况下在本地运行它——将 SCRAPER_URL 指向一个正在运行的 scraper:

bash
cd yozh-crawler
pip install -r requirements.txt
cp .env.example .env          # edit SCRAPER_URL if needed
python -m uvicorn src.main:app --reload --port 8001

基本用法

提交一个包含 seed_url 以及一个 scope。该调用会立即返回一个 job_id ;随后该爬取任务将在后台通过多个工作线程执行。

cURL
curl -X POST http://localhost:8001/api/v1/crawl 
  -H "Content-Type: application/json" 
  -d '{
    "seed_url": "https://example.com",
    "scope": {"mode": "same-domain", "max_depth": 2, "max_pages": 50,
              "per_domain_rps": 1.0, "per_domain_concurrency": 1},
    "scrape_options": {"proxy_type": "none"},
    "enable_scraping": false
  }'

响应内容仅为作业句柄:

JSON
{ "job_id": "crawl_abc123" }

在此,您可以选择直播活动,或者通过查询该任务获取完整记录。

探索与收获—— enable_scraping 切换

同一个爬行引擎支持双向运行。通过一个布尔值即可在低成本的发现模式和全负载采集模式之间进行切换——且每种模式都使用各自的代理配置,因此不会产生交叉影响。

enable_scraping: false

探索地图

轻量级抓取。抓取工具仍会渲染每一页(因此能发现由 JavaScript 生成的链接),但爬虫仅保留页面骨架——这非常适合用于网站地图、链接审核和差异检测。

  • 保持 url · parent_url · depth · status · took_ms
  • 支持上传原始HTML、截图和提取的数据
  • 使用更便宜的 crawl_proxy
  • 最小有效载荷,最快爬行速度
enable_scraping: true

完整采集

每个访问过的页面都会连同其完整的 ScrapeResponse — 原始 HTML、可选的截图以及您提取规则中的所有字段。一次爬取,一次结构化处理。

  • 保留每页的完整 ScrapeResponse 每页
  • raw_html · screenshot · 已提取 data
  • 用途 scrape_options.proxy_*
  • 通过 extract 规则以获取干净的 JSON
代理选择。 crawl_proxy 仅在 enable_scraping=false; scrape_options.proxy_* 仅在以下情况下使用 true。如果 crawl_proxynull,则 scrape_options 无论处于何种模式,都会使用代理。

爬网范围

范围限定了爬行行为:规定了爬行可以访问的范围,以及对每个主机的访问强度上限。它是 scope 请求中的对象。

字段类型默认值说明
modesame-domain · subdomains · all · regexsame-domain哪些链接属于范围之内。 regex 与……匹配 include_patterns.
include_patternsstring[][]URL 必须匹配的正则表达式模式才能被加入队列(由 regex mode / 作为白名单)。
exclude_patternsstring[][]即使 URL 原本在作用域内,也会将其剔除的正则表达式模式。
max_depthint3从种子节点开始的最大链接深度(种子节点深度为 0)。
max_pagesint500在抓取完成前,对访问的页面数设置硬性上限。
per_domain_rpsfloat1.0每个域的令牌桶补充速率(请求/秒)。
per_domain_concurrencyint1对单个域的最大并发请求数。
subdomains 的作用域定义较为简单。它将最后两个标签作为可注册域,因此会对“公共后缀列表”(Public Suffix List)中的主机产生过度匹配,例如 github.ioco.uk等主机时,会发生过度匹配。建议优先使用 same-domainregex

流式处理结果 (SSE)

每个任务都会暴露一个服务器发送事件流。通过读取该流,可以在发现页面的一瞬间就对其采取行动,而无需等待抓取完成。

cURL
curl -N http://localhost:8001/api/v1/crawl/crawl_abc123/events

该流会发出五种事件类型:

事件触发时机
stats定期进度快照(已访问 / 排队中 / 失败 / 去重跳过 / 超出范围 / 重试)。
page每个访问过的URL对应一个。在 ScrapeResponse 在采集模式下,在发现模式下仅包含精简元数据。
page_error一个在所有重试后仍失败的 URL。
done终端 — 抓取已正常完成。
cancelledTerminal — 抓取已取消。

一个 page 发现模式下的事件如下所示:

JSON
{
  "event": "page",
  "url": "https://example.com/docs/intro",
  "parent_url": "https://example.com/docs",
  "depth": 2,
  "status_code": 200,
  "took_ms": 812,
  "scrape_response": null
}

进展与结果

更喜欢轮询吗?任务记录可随时查询——包括在爬取过程中,此时可查询到迄今为止发现的页面。 /results 是该任务端点的别名,为与抓取工具保持一致而保留。

cURL
curl http://localhost:8001/api/v1/crawl/crawl_abc123
curl http://localhost:8001/api/v1/crawl/crawl_abc123/results
JSON
{
  "job_id": "crawl_abc123",
  "status": "running",
  "stats": {
    "visited": 47, "queued": 12, "failed": 0,
    "dedup_skipped": 9, "out_of_scope": 31, "retries_total": 2
  },
  "pages": [
    { "url": "https://example.com/", "parent_url": null,
      "depth": 0, "status_code": 200, "took_ms": 640 }
  ]
}
status 穿过 queuedrunningdone (或 failed / cancelled).

取消抓取

使用 DELETE。软取消是默认操作,也是安全的选择。

cURL
# soft — stop scheduling, let in-flight requests drain
curl -X DELETE "http://localhost:8001/api/v1/crawl/crawl_abc123?hard=false"

# hard — abort in-flight asyncio tasks immediately
curl -X DELETE "http://localhost:8001/api/v1/crawl/crawl_abc123?hard=true"
强制取消会导致爬虫程序成为孤儿。A ?hard=true 会中断爬虫正在处理的请求,但抓取程序无法得知这一点——它那边的页面渲染已经完成。除非必须立即停止,否则请优先使用软取消。

MCP

fastapi-mcp 已部署在 /mcp 作为 Streamable HTTP 端点。将 Point Claude 或 Cursor 指向该端点,相关工具便会自动显示:

  • health
  • create_crawl
  • get_crawl
  • get_crawl_results
  • cancel_crawl
~/.claude/settings.json
"open-crawler": {
  "type": "http",
  "url": "http://localhost:8001/mcp"
}
SSE stream_crawl_events 端点被有意排除在 MCP 之外——流式响应并不适用于请求/响应工具。

配置参考

请求 — CrawlRequest

字段类型默认值说明
seed_url字符串 (URL)必填爬取操作的起始 URL。
scopeCrawlScopedefaults边界与礼貌——参见“爬行范围”。
scrape_optionsScrapeOptionsdefaults按每页内容原样转发给抓取程序(url 被注入)。
crawl_proxyScrapeOptions · nullnull在发现模式下使用的廉价代理。仅 proxy_type / proxy_pool_id / proxy_geo 被读取。
enable_scrapingboolfalse保持每页 ScrapeResponse 内容(true) 还是仅保留检索元数据(false).

每页 — ScrapeOptions (已选中)

字段类型默认值说明
proxy_typenone · mobile · res_static · res_rotating · dc_static · …none代理池,页面通过该代理池获取路由。
devicedesktop · mobiledesktop视口 / 用户代理配置文件。
renderbooltrue使用浏览器渲染(JS生成的链接需要此操作)。
stealthbooltrue应用反检测加固措施。
wait_untildomcontentloaded · networkidledomcontentloaded当页面被视为准备就绪时。
screenshotboolfalse截取屏幕截图(采集模式)。
extractExtractRule · nullnullCSS/XPath 字段规则 → 结构化 data 按页面。
session_id字符串 · nullnull重用已认证的爬虫会话——请参阅“已认证的爬取”

环境变量

变量默认值备注
SCRAPER_URLhttp://web-scraper:8000上游抓取器(在 Compose 网络中使用 Docker 服务名称)。
WORKERS2并行爬取任务的数量。
QUEUE_MAXSIZE200待处理任务队列的深度。
JOB_TIMEOUT_MS3_600_000对一个爬取任务设置Wall-clock时间限制。
SCRAPER_JOB_TIMEOUT_MS120_000每页抓取请求超时。
MAX_RETRIES3发生临时故障时,每个请求的重试次数。
RETRY_HTTP_CODES[408,429,500,502,503,504]会触发重试的状态码。
RETRY_BACKOFF_MAX30.0指数退避的上界(秒)。
SESSION_MAX_ERROR_SCORE3.0会话过期阈值。
SESSION_MAX_USAGE50在 N 次使用后轮换会话。
SESSION_BLOCKED_CODES[401,403,429]可立即结束会话的代码。

API 参考

方法路径用途
POST/api/v1/crawl创建一个作业。返回 {"job_id":"…"}.
GET/api/v1/crawl/{id}任务记录——状态、统计数据、目前已浏览的页面。
GET/api/v1/crawl/{id}/results该工作记录的别名。
GET/api/v1/crawl/{id}/eventsSSE 流 (stats/page/page_error/done/cancelled).
DELETE/api/v1/crawl/{id}?hard=bool取消该作业(软取消或硬取消)。
GET/api/v1/health健康 + 抓取器可达性。

重要细节

无身份验证(v1)。所有端点均不进行身份验证——该设计适用于内部/可信网络。任何能够访问该端点的人都可以使用任意种子发送 POST 请求进行爬取,并将其转变为 SSRF 代理。请将其保留在您的 VPC 内或您自己的身份验证网关之后。
robots.txt 不会进行查询。爬虫会遍历所有在范围内的 URL,无论 /robots.txt。对于您不拥有的目标网站,您有责任遵守机器人协议和网站条款——请使用 exclude_patterns 和速率限制,以保持礼貌。
不支持持久化。任务驻留在内存中,并在容器重启时重置(与 scraper 行为一致)。若需确保数据持久性,请在页面到达时将 SSE 数据流导入您自己的存储(文件、Postgres、Kafka)。请定期重启长期运行的进程——已完成的任务会积存在存储中。
经过身份验证的爬取。在爬虫上创建一个会话(POST /sessions + POST /sessions/{id}/login),然后传递 scrape_options.session_id。抓取器会针对每个请求在客户端和服务器端传输 Cookie 及存储状态,因此每个被抓取的页面都能看到经过身份验证的状态。
实时示例

同域 — 安全的默认选项

仅停留在精确的种子主机上,限制深度与页数,保持礼貌抓取。发现模式(enable_scraping: false)只保留每个页面的骨架结构。


            

深受数据团队和人工智能开发者的喜爱

使用 Yozh 进行开发的用户怎么说

5.0 / 5 · 5 评测
GitHub
仅用一个下午就将我们内部的 Playwright 集群替换为 Yozh。MCP 端点直接接入我们的 Claude 代理——无需任何胶水代码,爬虫和数据提取工具便能正常运行。
Marcus Reinhardt 首席数据工程师 Northwind Analytics
X
预设系统是其杀手级功能。我们传入源名称,就能得到干净的 JSON 数据;其自动修复功能甚至在我们察觉之前就发现了亚马逊的两次布局变更。
Priya Nair 创始人 ScrapeStack
Reddit
终于出现了一个将代理和会话视为第一类对象的开源爬虫工具。我们将其部署在合作伙伴门户网站的登录墙后方——会话能够保持持久性,且跨区域的爬取结果始终保持一致。
Daniel Osei 后端工程师 Loopfeed
X
通过 MCP 将其连接到 Cursor 后,我的代理现在可以在任务进行中实时提取网页数据。通过 SSE 进行的流式爬取,正是代理工作流所缺失的功能。
Elena Kovac 人工智能工程师 Vektor Labs
GitHub
为了节省成本,我们放弃了付费的数据抓取 API,并做好了性能下降的准备——结果却事与愿违。现在采用自托管模式,无需按请求付费,而且输出数据结构比我们以前付费使用的还要简洁。
Sofia Almeida 工程经理 Tabbly
开源 · MIT 许可 · 84 ★

输入一个网址。观看网站内容实时加载

Yozh Crawler 与数据抓取工具位于同一个仓库中——一个 docker compose up ,您便可在自己的基础设施上拥有支持 MCP 的数据发现与提取功能。免费。永久免费。如果它能成为您技术栈中的一员,请为我们点个星。

Yozh Crawler + Scraper 根据 MIT 许可证发布。请随意使用、分叉和基于它进行开发。