AnyCrawl

监控(Monitors)

按计划追踪网页与价格变化,支持 diff 检测、AI 过滤,以及 Webhook 或邮件告警。

简介

Monitors(监控)用于持续追踪 URL 的变化。每个 monitor 按 cron 计划执行抓取,将结果与上一快照对比,并在检测到有意义的变化时发送通知。

核心能力:网页文本 diff、结构化价格提取、可选 AI 判断、Webhook/邮件通知、快照历史、按需立即检查。

监控类型

类型monitor_type默认 track_mode适用场景
网页"webpage""text"文档、博客、服务条款、状态页
价格"price""json"商品价格、库存、结构化字段

Monitor 基于 定时任务(Scheduled Tasks) 实现。创建 monitor 时会自动创建一条 1:1 关联的后台 scrape 定时任务,调度由 monitor API 统一管理。

MVP 说明: 请求体可包含多个 targets,但当前仅对 第一个 target 创建调度。多 target 支持将在后续版本提供。

API 端点

POST   /v1/monitors                         # 创建 monitor
GET    /v1/monitors                         # 列出 monitors
GET    /v1/monitors/:id                     # 获取详情
PATCH  /v1/monitors/:id                     # 更新
DELETE /v1/monitors/:id                     # 删除
POST   /v1/monitors/:id/pause                 # 暂停
POST   /v1/monitors/:id/resume                # 恢复
POST   /v1/monitors/:id/check                 # 立即触发检查
GET    /v1/monitors/:id/snapshots             # 快照列表
GET    /v1/monitors/:id/changes               # 变更列表
GET    /v1/monitors/:id/changes/:changeId     # 变更详情

快速开始

网页变更监控

每小时检查文档页,变更时通过 Webhook 告警:

curl -X POST "https://api.anycrawl.dev/v1/monitors" \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "文档更新监控",
    "monitor_type": "webpage",
    "cron_expression": "0 * * * *",
    "timezone": "Asia/Shanghai",
    "targets": [
      {
        "url": "https://example.com/changelog",
        "engine": "auto"
      }
    ],
    "diff_options": {
      "only_main_content": true,
      "min_change_ratio": 0.01
    },
    "notify_options": {
      "channels": ["webhook"],
      "only_meaningful": true
    }
  }'

响应示例

{
  "success": true,
  "data": {
    "monitor_id": "550e8400-e29b-41d4-a716-446655440000",
    "scheduled_task_id": "660e8400-e29b-41d4-a716-446655440001",
    "track_mode": "text",
    "next_execution_at": "2026-07-17T13:00:00.000Z"
  }
}

价格监控

每 15 分钟提取并对比商品价格:

{
  "name": "商品价格追踪",
  "monitor_type": "price",
  "cron_expression": "*/15 * * * *",
  "targets": [
    { "url": "https://shop.example.com/product/12345", "engine": "auto" }
  ],
  "extract_schema": {
    "type": "object",
    "properties": {
      "price": { "type": "number" },
      "currency": { "type": "string" },
      "in_stock": { "type": "boolean" }
    },
    "required": ["price"]
  },
  "notify_options": {
    "channels": ["webhook"],
    "thresholds": { "price_change_pct": 5 }
  }
}

monitor_type"price" 时,必须提供 extract_schema

请求参数

核心配置

参数类型必填默认值说明
namestring-名称(1–255 字符)
monitor_typestring"webpage""webpage""price"
cron_expressionstring-标准 5 段 cron
timezonestring"UTC"时区
targetsarray-监控目标 URL 列表
goalstring-AI 判断用的自然语言目标
track_modestring自动推断"text" / "json" / "mixed"
extract_schemaobject条件必填-结构化提取 schema(price 必填)

diff_options

参数说明
only_main_content仅对比正文,默认 true
ignore_selectors排除包含指定字面短语的文本行;不是 CSS 选择器
min_change_ratio最小变更比例(0–1)

notify_options

参数说明
channels"webhook" 和/或 "email"
email_recipients启用 email 时必填
only_meaningful过滤噪声,默认 true
thresholds.price_change_pct价格变更百分比阈值

邮件通知需在自托管环境中配置 ANYCRAWL_SMTP_*,详见 Docker 部署

变更检测流程

  1. 抓取 — 后台定时任务执行 scrape
  2. 标准化 — 提取正文、应用字面文本行排除
  3. 快照 — 存储内容与 hash
  4. Diff — 文本 diff 或 JSON 字段对比
  5. 判断 — 设置 goal 时由 AI 过滤噪声
  6. 通知 — 发送 Webhook 或邮件

管理 Monitor

// 生命周期
await client.pauseMonitor(monitorId);
await client.resumeMonitor(monitorId);
await client.runMonitor(monitorId); // 立即检查

// 历史
const snapshots = await client.getMonitorSnapshots(monitorId, { limit: 20 });
const changes = await client.getMonitorChanges(monitorId, { limit: 20 });
const detail = await client.getMonitorChange(monitorId, changeId);

立即检查返回 202;若已有检查进行中则返回 409

Webhook 事件

通过 Webhooks 订阅:

事件说明
monitor.check.completed检查完成(含摘要)
monitor.changed网页内容有意义变更
monitor.price.changed价格或结构化字段变更
monitor.error检查失败

Payload 内联 diff 数据,无需额外请求 changes API。

JavaScript SDK

安装 0.0.6+ 版本:

pnpm add @anycrawl/js-sdk

完整 API 见英文文档 Monitors 或 SDK README。

限制

限制
实际调度的 target 数1(MVP 仅首个)
请求体 targets 上限50
邮件收件人20
内联快照大小默认 256 KB(ANYCRAWL_MONITOR_MAX_INLINE_CHARS

相关文档

检查恢复、状态与分页

每次检查在 DB 中记录 pending → ready → processing → completed/failed,抓取终态与后处理意图一起提交。Worker 用 lease 与 fencing 恢复失败处理;快照、变化、通知意图及处理终态原子提交。同一 monitor 在抓取和后处理期间只有一个活跃检查,skip 跳过重叠 cron,queue 延后;手动检查也遵守单飞。监控不占普通 scheduled-task 配额。

Monitor GET 返回 in_progress、last_check_state、last_check_at、last_check_error、pause_reason 和 revision。有效运行状态为 is_active && !is_paused;自动暂停直接 resume。409 的 code 分为 MONITOR_PAUSED 与 MONITOR_CHECK_IN_PROGRESS,不能统一当作“正在检查”。

PATCH 在事务内合并并验证最终配置。嵌套 options 保留未提交的兄弟字段;goal=null 清除说明及抽取 prompt;price/json/mixed 必须保留可用 schema。monitor_type 不支持修改,未知顶层字段返回 400,target options 不支持模板。有效抓取、模式、goal 或文本排除规则变化会开始新 revision 的基线;仅通知/阈值变化保留原基线。复杂 JSON schema 在请求和 UI 编辑过程中保留原结构。

首次无效抽取返回 error,不建立健康基线。完整正文保存在数据库;快照详情 /v1/monitors/:id/snapshots/:snapshotId 返回预览,含 content_truncated/content_length/content_complete/monitor_revision。预览默认 262144 字符,比较正文上限默认 2000000 字符;超过比较上限是错误,不是 same。旧不完整正文保留历史,但不参与新基线。

快照、单 monitor changes 和 /v1/monitors/changes 返回 {success,data,pagination:{has_more,next_cursor}}。下一页使用服务器 cursor,offset 仍兼容;时间相同时按 uuid 排序。changes 可传 include_diff_text=false,展开时读取单条详情。

notified 仅在至少一个 SMTP 收件人被接受或 Webhook HTTP 2xx 后为 true。notification_status 区分 none/pending/queued/delivered/failed/skipped;legacy 的历史 boolean 无法证明送达。/v1/monitors/:id/checks 返回检查历史,/v1/monitors/:id/notifications 返回按渠道/收件人的状态与错误,change detail 也包含 notifications。错误检查同样可以发 email;SMTP 未配置或临时失败会有限重试并保留原因。稳定 Delivery-ID/Message-ID 支持识别重试,但不保证邮件 exactly-once。

AI 判断服务不可用或组合 diff 输入不完整时记录 meaningful=null、status=unavailable/incomplete,保留变化证据。固定 country routing 不支持,capabilities.location=false;不能用 location 字段证明真实出口。价格图按 URL/path/currency 分组,并说明只展示已加载的变化点。

恢复 Worker 随 scheduler 启动,也可单独 --queues=monitor。默认 ANYCRAWL_MONITOR_MAX_ATTEMPTS=5、RETRY_DELAY_MS=5000、LEASE_MS=120000、POLL_MS=5000(后三者均以 ANYCRAWL_MONITOR_ 为前缀)。ANYCRAWL_MONITOR_RETENTION_DAYS 默认 0;显式启用后分批清理新工作流历史,保护健康基线、保留引用、待送达记录及 legacy。升级不自动补发旧告警。

const feed = await client.listMonitorChanges({ limit: 20 });
const page = await client.getMonitorSnapshotsPage(monitorId, { limit: 20 });
if (page.data[0]) await client.getMonitorSnapshot(monitorId, page.data[0].uuid);
const checks = await client.getMonitorChecks(monitorId);
const notifications = await client.getMonitorNotifications(monitorId);