标识与响应
网页对象 schema · 「必须捕获」列指事后无法补算,缺了只能重抓
| field字段 | value取值 | must capture必须捕获 |
|---|---|---|
| url请求地址 | https://news.example.tw/post/48213 | |
| final_url最终地址 | https://news.example.tw/post/48213 | |
| fetched_at抓取时间 | 2026-08-15T07:47:52Z | |
| http_statusHTTP 状态 | 200 | |
| redirect_chain重定向链 | [] | 是 |
| response_headers响应头 | etag: "abc123" · last_modified: 2026-08-14T22:10:03Z | 是 |
| robots_snapshot抓取时刻的 robots 同期证据 | User-agent: *\nCrawl-delay: 2\n… 共 412 字节 | 是 |
⚠️ redirect_chain 是空数组 [],不是 null。空数组表示「本次没有重定向」,null 表示「这次抓取没产生这个字段」(如 not_modified)。两者语义不同,注释必须区分。
⚠️ robots_snapshot 是抓取时刻的同期合规证据,与采样器按域名存的 sampler:robots_rule 不同 —— 后者会在复核时刷新。两者不可互相替代,名字也不可互借;导出给外部时字段名是 robots_rule_content。半年后对方改 robots 来追责,要能证明抓时是允许的。
内容与结构化载荷
对 CSR 站,structured_payload 不是元数据,是内容的结构化版本
| field字段 | value取值 | must capture必须捕获 |
|---|---|---|
| raw_html渲染前 HTML | 48,210 字节 | 是 |
| rendered_html渲染后 HTML | 186,940 字节 | |
| structured_payload结构化载荷 | __NEXT_DATA__ 命中 · jsonld 2 条 · microdata 无 | |
| raw_text_length渲染前文本长度 | 180 | 是 |
| text_length渲染后文本长度 | 3,456 | |
| content_hash内容哈希 | a1b2c3d4e5f60718293a4b5c6d7e8f90 | |
| simhash相似哈希 | e7c19a4b80d3f562 |
⚠️ raw_text_length 入库时算一次,别留给以后重扫。link_list 带 injected_by_js 可反推渲染前链接数,但文本这侧没有对应字段,不当场算,失效检测每次都要重解析 raw_html。
⚠️ content_hash 与 url_hash 同规格:SHA-256 取前 16 字节,小写 hex,32 字符。算法或长度变更等同于全库重建。
语种三字段
语种识别在采样器完成,下载器只透传
| field字段 | value取值 | note说明 |
|---|---|---|
| lang语种 | zh-Hant | 外部标准名(<html lang> 与 BCP 47),不改为 language |
| region | TW | 由 TLD + IP 归属推定 |
| jurisdiction法域 | TW | 每个法域一个独立取值,TW / HK / MO 不并入 CN |
| lang_source语种来源 | domain_rule | caller / domain_rule / unknown,下游据此判断可信度 |
⚠️ 三字段独立存储,禁止合并。技术层只负责如实标注,合并与否是下游策略层的决定 —— 字段合并了就再也拆不开。
link_list
链接不止 URL · injected_by_js 是本系统独有的信号 · 本对象共 42 条,下表为前 5 条
| url链接地址 | anchor_text锚文本 | rel | dom_positionDOM 位置 | injected_by_js是否 JS 注入 |
|---|---|---|---|---|
| https://news.example.tw/post/48214 | 下一篇 | null | content | true |
| https://news.example.tw/topic/finance | 財經 | null | nav | false |
| https://news.example.tw/author/1182 | 陳小明 | null | content | true |
| https://partner.example.com/ad/22 | 贊助 | nofollow | content | true |
| https://news.example.tw/about | 關於我們 | null | footer | false |
- link_count链接总数
- 42
- js_injected_link_countJS 注入链接数
- 38
- 非 JS 注入 = 前者 − 后者
- 4
⚠️ js_injected_link_count 是 link_count 的子集,不是补集。写反了 link_ratio 会静默反向 —— 不报错、不崩溃、结论相反。
⚠️ injected_by_js 不在抓取时打标,以后永远分不出来。rel 与 dom_position 也必须回传给调度器:只传 URL 会让 nofollow 无人遵守,列表页优先也判断不出来。
network_log
只存元数据(URL / 方法 / 状态 / 大小 / 类型),体积仅 ×0.1 · 本对象共 61 条,下表为 xhr 类前 5 条
| url请求地址 | method方法 | http_statusHTTP 状态 | size体积(字节) | type资源类型 |
|---|---|---|---|---|
| https://api.example.tw/v3/article/48213 | GET | 200 | 18,402 | xhr |
| https://api.example.tw/v3/comment/48213 | GET | 200 | 6,110 | xhr |
| https://api.example.tw/v3/related | GET | 200 | 2,884 | xhr |
| https://track.example.com/collect | POST | 204 | 0 | xhr |
| https://api.example.tw/v3/user/profile | GET | 200 | 944 | xhr |
⚠️ 不存响应体 —— JS bundle 是元数据的 50~200 倍。v1 不做离线分析,但要做一件实时的事:算 health_signal。接口逆向是 v2 §四 的事,要改契约。
渲染指标与 health_signal
health_signal 在下载器侧算好,随 report 与探针响应一起回,数据本来就在这边
渲染指标
| field字段 | value取值 |
|---|---|
| render_path渲染路径 | obscura |
| render_duration_ms渲染耗时(毫秒) | 812 |
| dom_node_countDOM 节点数 | 1,234 |
| console_errors控制台错误 | [] |
health_signal(健康信号)
| field字段 | value取值 |
|---|---|
| xhr_total_count | 12 |
| xhr_error_count | 0 |
| xhr_throttled_count | 0 |
| xhr_denied_count | 0 |
| has_console_error | false |
| redirect_target_hash | a1b2c3d4e5f60718… |
⚠️ console_errors 是空数组,不是 null;has_console_error 只传布尔,不传内容。前者在网页对象里,后者在 report payload 里,不是同一个东西。
⚠️ 不识别「取正文的那个 XHR」。一个 CSR 页面几十个 XHR,判据定不下来。只回四个计数,由调度器按比例判断(DEV-scheduler.md §9.4)。本页不下结论。
⚠️ 让调度器去 GET /v1/objects/{object_id} 自己算,单机每天数十万次额外读,且会把调度器与网页对象 schema 绑死 —— 拆分的意义就没了。所以摘要在这边算,约 60 行代码,数据零额外采集。
相关
同一条 URL 在其他表里的记录
| where位置 | key | actions操作 |
|---|---|---|
| 抓取状态 | downloader:fetch_result:7f2a9c1d4e6b08a35c2f91d7e4b06a18 | 查看 |
| 域名限速 | downloader:domain_runtime:news.example.tw | 查看 |
| 网页库 | SeaweedFS 3,01637037d6 | 返回列表 |
⚠️ 调度器侧的 scheduler:url_task 与 scheduler:url_result 不在此列。契约里没有下载器读取它们的边,没有边就是不能传。