采样器提供的接口
CONTRACT.md §四 · 前三个对内,后三个对外部消费方开放
| endpoint接口 | caller调用方 | note说明 |
|---|---|---|
| POST /v1/domains | 调度器、人工 | 提交待判定,异步立即返回 {accepted_count, task_ids}。reason:new | recheck | manual |
| POST /v1/recheck | 调度器 | {domain, signal, detail}。signal 四值全部由调度器的统计发出 |
| GET /v1/rules/{domain} POST /v1/rules/batch | 调度器 | 查询域名规则。调度器冷启动时用批量 |
| GET /v1/undetermined-domains | 外部 | 只读观察。不产生认领,不改变任何状态。返回 {total_count, undetermined_domain_list} |
| POST /v1/undetermined-domain-claims | 外部 | 外部的主入口。claim_ttl_seconds 上限 7 天,超过按上限截断并在响应中说明 |
| POST /v1/domain-verdict-hints | 外部 | 回报判定结果。外部只能提交建议,采样器确认后才写规则表 |
| POST /v1/api-endpoint-hints | 下载器 | v2 才启用 接口逆向线索。{domain, api_endpoint, sample_url_list, confidence_score} |
⚠️ 接口路径规则:/v1/{名词复数},kebab-case,不用缩写。/v1/hints ✗,/v1/api-endpoint-hints ✓。查询参数同样适用字段命名规则,且同一语义在查询参数与 body 里必须同名。
⚠️ v2 的 /v1/api-endpoint-hints 必须走采样器,不能由下载器直接告诉调度器。域名级配置只能有一个所有者,否则两边写同一份规则会冲突。
采样器调用的接口
CONTRACT.md §一 · 本服务没有 HTTP 客户端
| endpoint接口 | direction方向 | note说明 |
|---|---|---|
| POST scheduling-url/v1/rules | 采样器 → 调度器 | 判定结果回调。幂等键 domain + verified_at,verified_at 必须单调,收到更旧的值丢弃并返回 200 |
| POST crs.tongsou.com/v1/render | 采样器 → 下载器 | 取页面。should_render = true 取样本页,false 取 robots.txt 与 sitemap.xml |
⚠️ 一次 /v1/render 调用同时拿到双取两侧:raw_html 是渲染前的原始响应,rendered_html 是渲染后。请求量减半,且是浏览器 UA 取的 —— 不少站对非浏览器 UA 返回不同 HTML,纯 HTTP 客户端拿到的不能代表真实内容。
⚠️ 本服务不直连目标站点。域名限速需要单点保证 —— 一个新域名首次判定若走直连,是 7 次以上的集中探测,封禁往往就发生在这里。
verdict 四值与调度器分支
CONTRACT.md §三 · 这四个值决定调度器怎么处理该域名的所有链接
| verdict判定结论 | meaning含义 | scheduler action调度器动作 |
|---|---|---|
| csr | 确定是 CSR | 正常入队 |
| partial | 分歧大 / 混合 | 入队,降优先级 |
| ssr | 传统爬虫可抓 | 记录,丢弃该域名后续链接 |
| unknown | 判定失败 | 记录,丢弃该域名后续链接;重采与导出归采样器 |
⚠️ 收到 /v1/rules 回调时,无论 verdict 是哪个值,调度器一律删除 domain_judgement_task。
⚠️ unknown 不再「转人工」。调度器侧不做第二套重试 —— 两边都重试会导致重复提交同一个域名。
回调 payload 的字段
CONTRACT.md §三 POST /v1/rules
| field字段 | required必填 | note说明 |
|---|---|---|
| domain域名 | 是 | 幂等键的一半 |
| verdict判定结论 | 是 | 四值枚举 |
| verified_at判定确认时间 | 是 | 幂等键的另一半,必须单调 |
| wait_selector | 否 | 推不出就留空,下载器退回 networkidle0 |
| lang语种 | 否 | 外部标准名,不改为 language |
| region | 否 | 由 TLD + IP 归属推定 |
| jurisdiction法域 | 否 | 每个法域一个独立取值,不做合并 |
| min_interval_ms最小请求间隔(毫秒) | 是 | 已取过 max,下游禁止再取 |
| disallow_prefix_list | 是 | 必须回传,否则 robots 的 Disallow 全系统无人执行 |
| list_link_ratio | 否 | 只取自列表页样本,与正文无关 |
| verdict_reason判定结论说明 | 否 | 自由文本,不参与任何分支 |
导出接口的字段可空性
CONTRACT.md §四 · undetermined_domain_list 的每一项
| field字段 | required强制 | note说明 |
|---|---|---|
| domain域名 | 是 | |
| undetermined_reason判不出来的原因 | 是 | 九个取值之一 |
| judgement_attempt_count判定尝试次数 | 是 | |
| first_submitted_at首次提交时间 | 是 | 时态词成对:first_ 与 last_ |
| last_attempted_at最后一次判定尝试时间 | 是 | 不是最后抓取时间 |
| attempted_sample_url_list已尝试的样本页 | 否 | 数组带 _list 后缀 |
| last_http_status最后一次 HTTP 状态 | 否 | 没拿到响应时为 null |
| last_raw_text_length最后一次渲染前文本长度 | 否 | null 是「没取到」,0 是「取到了但空」 |
| last_fail_reason最后一次失败原因 | 否 | |
| min_interval_ms最小请求间隔(毫秒) | 强制 | 技术层:不下发,限速的单点保证彻底失效 |
| disallow_prefix_list | 强制 | 合规层:转出义务必须同时转移依据 |
| robots_rule_content | 强制 | 合规层。不是 robots_snapshot |
⚠️ 最后三个字段是强制项,不是可选。把域名交给外部却不给 robots 规则,等于转出义务而不转移依据;外部违规抓取,追责会追回导出方。
跨服务约定与变更规则
CONTRACT.md §五、§七
| item事项 | rule约定 |
|---|---|
| 认证 | 服务间固定 token。外部消费方使用独立 token,可单独吊销,只能访问 §四 的三个导出接口 |
| 重试 | 失败指数退避,上限 3 次 |
| 幂等 | rules 用 domain + verified_at;domain-verdict-hints 用 claim_id + domain。都在 payload 里,不引用内部字段 |
| 存储隔离 | 三服务各自独立数据,不共享表。外部消费方不接触任何 keyspace |
| 跨服务传递 | 只能通过 CONTRACT.md 里已定义的边,没有边就是不能传 |
| 契约变更 | 三方确认。涉及导出接口的变更还需通知已接入的外部消费方。字段只增不删,废弃字段标 deprecated,接收方必须容忍未知字段 |
⚠️ 本服务不能写 scheduler:domain_health_runtime,调度器不能写 sampler:domain_rule。需要对方的数据走接口拿副本,副本表名带 _replica 并注明只读 —— 调度器那边叫 scheduler:domain_rule_replica。
⚠️ crs: 不得作为任何 key 前缀,它与系统名撞义。本服务一律用 sampler:。
M0:采样器完全不参与
CONTRACT.md §六 · DEV-sampler.md §十一
M0 阶段规则由人工直接 POST scheduling-url/v1/rules,本服务只需先能落盘和回调。跑通四步再接自动化。
| order顺序 | item事项 | note说明 |
|---|---|---|
| 1 | 规则落盘 + POST /v1/rules 回调 | M0 只需这一步 |
| 2 | judgement_task 超时回收 | 回调可靠性的一部分,不是优化 |
| 3 | 判定逻辑 | 调 /v1/render,算两个 ratio |
| 4 | 样本选取 | sitemap / 提链 / 排除规则 |
| 5 | robots 获取与解析 | 解调度器的循环依赖 |
| 6 | wait_selector 推导 | 最有价值的产出 |
| 7 | 语种识别 | 繁简区分是难点 |
| 8 | 待定池 + 退避重采 | 出口一,不依赖外部 |
| 9 | 导出三接口 | 出口二,加速器 |
| 10 | 复核流程 | 系统开始自我改进 |
⚠️ 第 8 步必须早于第 9 步。先有自动出口再有导出接口,否则一旦外部没接上就是黑洞。
边界清单
DEV-sampler.md §十二 · 采样器只写自己的 keyspace,通过 API 回调调度器
归采样器
判定域名 verdict |
wait_selector 推导 |
| 语种识别 |
| robots 获取与解析 |
| 域名级 URL 规范化规则 |
| 待定域名的重采与导出 |
不归采样器
| URL 发现与去重 —— 调度器 |
限速执行、disallow_prefix_list 执行 —— 调度器 |
| 异常信号统计 —— 调度器 |
| 域名健康与熔断 —— 调度器 |
| 渲染与对外请求 —— 下载器 |
| 正文抽取与倒排索引 —— 下游,不在六份文档内 |
⚠️ 熔断与判定完全解耦,而且是双向的。熔断不需要把域名推给采样器:采样器有自己的复核周期,它重采一个死站会得到 unknown,自己就把域名放进待定池了。采样器也不需要告诉调度器「我被封了」:调度器自己的请求会撞到 403,熔断自己会跳闸。少一条边,就少一处需要定义的失败语义。