# 爬虫数据 QC 结果文档

> 活文档：Tier1 自动体检 + Tier2 人工裁定逐批追加。全量明细见同目录 `qc_tier1_<date>.md/.json`。

## 一、口径（2026-09-25 确认）

- **主键 = `Script_name`**。配置编号**已弃用**：历史遗留（当时调度=50 个/批分批跑，编号=当时数组快照序），现行调度不看它 → **QC 不校验编号**。
- **停滞 > 30 天** 算异常。
- **先列清单，再定批量策略**；Tier1 不改任何数据。
- 三层：Tier1 全自动出清单 → Tier2 人工（10 个/批）只处理异常 → Tier3 抽样反验判据。

## 二、Tier 1 首跑结果（2026-09-25）

config 条目 2114 | md5 9dd71a40b432 | gov_raw 580796 行 | script_name 空 3669（0.63%）

| 维度 | 条数 | 涉及脚本 | 性质 |
|---|---|---|---|
| D1 config 条目自身问题 | 122 | 90 | 已校准：真问题=未知参数 121 + 同脚本同参数重复 1 |
| D2 孤儿脚本（磁盘有、config 无） | 43 | 43 | 真问题：永不更新 |
| D3 无 --pages 且有全站翻页风险 | 231 | 231 | 判据待收紧 |
| D4 库内脚本名磁盘查无此文件 | 62 | 62 | 真问题（含 `luan`/`jz`/`kmyl` 等非文件名垃圾） |
| D5 config 注册但库内 0 行 | 190 | 190 | 真问题：空跑 |
| D6 库有数据但不在 config | 22 | 22 | 待判：改名/退役 |
| D7 停滞 >30 天 | 495 | 495 | 真问题（分档见下） |
| D8 行数≥30 却全无附件 | 1033 | 1033 | **高危候选池**，需页面级核查 |
| D9 存在空正文行 | 302 | 302 | 真问题 |
| D10 FTS 计数差（gov_search 634,551 vs gov_raw 580,796） | — | — | 需先确认 gov_search 服务范围 |
| D11b 空名行站点→候选脚本 | — | — | 25 个站点有候选脚本，可填充 |

### D1 假阳性说明（重要，自我纠正）

Tier1 v1 把 `args 为空`(718) 与 `sync_mode 非 direct_server`(432) 判为异常 —— **错**：调度器对二者都有默认值（日增量默认 1 页是**正常设计**）。因此「有问题的脚本 1917/2034」这个数字是虚的。
→ 加判据前必须先用 `crawl_scheduler_v2.py` 的真实解析行为校准。

### D7 停滞分档

    30~90 天   254 个
    90~180 天  124 个
    180~365 天  45 个
    >365 天     64 个（含 3894 天等古老站点，多为源站已死）

⚠️ 停滞 ≠ 爬虫坏了：**先证源站，再判爬虫**。

## 三、待裁定清单（先出清单，不批量动）

| # | 事项 | 规模 | 状态 |
|---|---|---|---|
| 1 | D1 判据收紧（剔除 args/sync_mode 假阳性） | 1150 条 | 待做 |
| 2 | D3 判据收紧（522 个"不支持 --pages"需逐个确认） | 522 | 待做 |
| 3 | (script,args) 完全重复 → 会重复跑 | 1 | 待定 |
| 4 | 孤儿脚本 43 个：注册 or 归档 | 43 | 待定 |
| 5 | 库内脚本名查无文件 62 个 / 13,876 行 | 62 | 待定 |
| 6 | 注册但 0 行 190 个：修 or 注销 | 190 | 待定 |
| 7 | 停滞 495 个：逐站证源站 | 495 | 待定 |
| 8 | 疑似无附件 1033 个：页面级抽样核查 | 1033 | 待定 |
| 9 | 空正文 302 个脚本 | 302 | 待定 |
| 10 | 空 script_name 3,669 行是否可填充 | 3669 行 | 待定 |
| 11 | FTS 计数差 +53,755：确认 gov_search 服务范围 | 1 | 待定 |

## 四、批次记录（Tier 2，10 个/批）

（尚无 —— 等 Tier1 判据收紧后开始）

### 补充：日跑失败/超时（证据口径，取代 D3 静态判据）

- 数据源 `run_logs`（95,568 次运行 / 2026-07-30 ~ 2026-09-25）→ 全量见 `qc_timeout_20260925.md/.json`
- 有失败记录的脚本 **673** 个：持续型 **17**（优先）/ 反复型 41 / 偶发型 615
- 类型：其他 333 / 超时 234 / 站点不可达 106
- ⚠️ D3 静态判据（无 --pages + 全站翻页风险）实测精确率仅 8%（19/231）且漏 217 个，**已废弃**，本表取代之

**持续型清单（失败率≥30% 且最近一次仍失败，优先处理）**

- `crawl_wenshang_gggs.py` ｜ 超时 ｜ 运行34 失败17(50%) ｜ 末次 2026-09-25 站点不可达
- `crawl_yanshou100.py` ｜ 超时 ｜ 运行2 失败2(100%) ｜ 末次 2026-08-21 超时
- `crawl_hbqj_eia.py` ｜ 超时 ｜ 运行1 失败1(100%) ｜ 末次 2026-08-01 超时
- `crawl_longtan_zcfg.py` ｜ 其他 ｜ 运行47 失败35(74%) ｜ 末次 2026-09-25 脚本异常
- `crawl_luanxian_854.py` ｜ 其他 ｜ 运行47 失败28(60%) ｜ 末次 2026-09-25 脚本异常
- `crawl_quanjiao_tzgg.py` ｜ 其他 ｜ 运行47 失败25(53%) ｜ 末次 2026-09-25 脚本异常
- `crawl_lufeng.py` ｜ 其他 ｜ 运行48 失败22(46%) ｜ 末次 2026-09-25 脚本异常
- `crawl_yjgx.py` ｜ 其他 ｜ 运行49 失败15(31%) ｜ 末次 2026-09-25 脚本异常
- `crawl_nc_hjbha.py` ｜ 其他 ｜ 运行13 失败11(85%) ｜ 末次 2026-08-19 脚本异常
- `crawl_ahgc.py` ｜ 其他 ｜ 运行5 失败5(100%) ｜ 末次 2026-08-07 脚本异常
- `jd_kfq` ｜ 其他 ｜ 运行5 失败4(80%) ｜ 末次 2026-08-07 脚本异常
- `jd_xnz` ｜ 其他 ｜ 运行7 失败4(57%) ｜ 末次 2026-08-07 脚本异常
- `crawl_yima_jczwgk.py` ｜ 其他 ｜ 运行3 失败3(100%) ｜ 末次 2026-08-19 脚本异常
- `crawl_smx_sthj.py` ｜ 其他 ｜ 运行3 失败3(100%) ｜ 末次 2026-08-19 脚本异常
- `crawl_fengkai_hpgs.py` ｜ 其他 ｜ 运行3 失败3(100%) ｜ 末次 2026-08-19 脚本异常
- `crawl_dxhb.py` ｜ 其他 ｜ 运行1 失败1(100%) ｜ 末次 2026-08-01 脚本异常
- `crawl_anyang_sthj.py` ｜ 其他 ｜ 运行1 失败1(100%) ｜ 末次 2026-08-07 失败


### 持续型 17 个 · 报错取证结论（2026-09-25）

| 脚本 | 站点 | 性质 | 真实报错/结论 |
|---|---|---|---|
| `crawl_wenshang_gggs.py` | 汶上县-公告公示 | 真bug·Playwright | `goto exc: TimeoutError / 列表未渲染`（Playwright 页未渲染，间歇 50%） |
| `crawl_yanshou100.py` | yanshou100-环保等公示 | 非真失败 | 脚本文件不存在 → config 挂着但磁盘没有 |
| `crawl_hbqj_eia.py` | 潜江市人民政府-建设项目环境影响评价公示 | 待实跑 | `[TIMEOUT]`（仅跑过 1 次）→ 需实跑 |
| `crawl_longtan_zcfg.py` | 龙潭区人民政府-政策法规 | 疑误判 | error_detail 是正常日志（共9页/本次爬取5页），疑被调度器误判失败 → 需实跑 |
| `crawl_luanxian_854.py` | 滦州市人民政府-服务事项 | 真bug·FTS抢锁 | line156 `DELETE FROM gov_search WHERE site_name=?` → sqlite3.OperationalError: database is locked |
| `crawl_quanjiao_tzgg.py` | 全椒县人民政府-通知公告 | 真bug·FTS抢锁 | line219 `DELETE FROM gov_search WHERE rowid IN (...)` → 同因（手写 DELETE FTS + 长事务抢锁） |
| `crawl_lufeng.py` | 陆丰市人民政府-建设项目环境影响评价 | 真bug·javascriptURL | `[FETCH ERROR] javascript:void(0): unknown url type: javascript` → 把 javascript: 链接当 URL 抓 |
| `crawl_yjgx.py` | 阳江滨海新区（阳江高新区）-环境保护信息 | 待实跑 | 日志正常（列表页1-4/5 已抓到）→ 需实跑 |
| `crawl_nc_hjbha.py` | 南昌市生态环境-政府信息公开 | 待实跑 | 日志正常（19 条已列出），真错在后段被截断 → 需实跑 |
| `crawl_ahgc.py` | 贵池区环评审批 | 待实跑 | traceback 显示跑的是 /mnt/data/crawler/ 旧副本（非 /root/gov_crawler）→ 需实跑取证 |
| `jd_kfq` | 江都区开发区-通知公告 | 非真失败 | 脚本文件不存在（本地降级站，本机跑）→ 应从服务器 QC 排除 |
| `jd_xnz` | 江都区仙女镇-通知公告 | 非真失败 | 脚本文件不存在（本地降级站，本机跑）→ 应从服务器 QC 排除 |
| `crawl_yima_jczwgk.py` | 义马市-基层政务公开行政许可 | 待实跑 |  |
| `crawl_smx_sthj.py` | 三门峡市生态环境局-法定主动公开 | 待实跑 |  |
| `crawl_fengkai_hpgs.py` | 封开县-建设项目环评 | 待实跑 |  |
| `crawl_dxhb.py` | 东乡环境保护 | 待实跑 |  |
| `crawl_anyang_sthj.py` | 安远县-生态环境局 | 待实跑 |  |

> **QC 口径修正**：本地降级站（`*_local.py` / 无 .py 后缀的 jd_kfq、jd_xnz 等）在服务器跑必然失败，**必须从服务器侧 QC 排除**，否则会持续误报。


## 六、修复记录（Tier 2 执行）

### 2026-09-25 · 批 1：去掉 2 个脚本的「整站清空再重灌」DELETE

- **对象**：`crawl_luanxian_854.py`（滦州市-服务事项）、`crawl_quanjiao_tzgg.py`（全椒县-通知公告）
- **症状**：`sqlite3.OperationalError: database is locked`，失败率 60% / 53%（持续型）
- **根因**：两脚本开头执行 `DELETE FROM gov_search ...` + `DELETE FROM gov_raw WHERE site_name=?`（整站清空再重灌）
  → ① 大事务 + 日跑并发 → 抢锁崩溃；② 更危险：中途超时/异常会把**整站数据清空**
- **为什么可以安全去掉**：`page_url` 有 UNIQUE 索引 `idx_gov_raw_page_url`，且两脚本分别用
  `INSERT OR IGNORE` / `INSERT OR REPLACE` → 本来就幂等；DELETE 纯属多余
- **改法**：删掉两条 DELETE（+ 保留 commit 语义），连接后加 `PRAGMA busy_timeout=60000`
- **验证**：两脚本实跑 **EXIT=0**（原 60%/53% 失败）；行数 **50→50 / 20→20 未丢数据** ✅
- **备份**：`Archive/crawl_luanxian_854.py.bak_20260925_delwholesite`、`Archive/crawl_quanjiao_tzgg.py.bak_20260925_delwholesite`
- **脚本**：`fix_delete_wholesite.py`（含 ast 校验，锚点不唯一则整体不落盘）

### 2026-09-25 · 批 2：全库 49 个「整站 DELETE」脚本批量清理

- **扫描**：全库 `DELETE FROM gov_raw WHERE site_name=?` → **49 个**，全部注册日跑；全部为幂等插入（`INSERT OR IGNORE/REPLACE`）→ 判定**全部可安全去掉**
- **工具**：`fix_delete_wholesite_batch.py`（dry-run 默认；安全闸 = 幂等插入校验 + 锚点唯一 + ast 校验 + 备份 `Archive/*.bak_20260925_delwholesite` + 残留复查）
- **结果**：注释 DELETE 行 —— 24 个 2 行 / 15 个 1 行 / 4 个 3 行；24 个顺带加 `PRAGMA busy_timeout=60000`
- **正确保留 1 处**：某脚本 `DELETE ... WHERE site_name=? AND publish_date < ?`（只删 CUTOFF 前老数据）→ 属正常保留策略，**未动**
- **校验**：`py_compile` **49/49 通过**；残留未注释 DELETE 行 = 1（即上述正常逻辑）；备份 51 份
- **实跑抽验**：`crawl_lufeng.py` **EXIT=0 且新增 38 条**（原失败率 46%+、数据停在 2025-10-20 → 顺带治好）、`crawl_lufeng_tzgg.py` EXIT=0、`crawl_fjql.py` EXIT=0（75 条）、批 1 的 5 个（平罗县/泉港区/米易/石大胜华/大冶）全部 EXIT=0 且行数 560/450/180/146/120 未丢
- **回归核对**：49 站行数 vs 基线 → 核对 45 站，**下降 0 个 ✅**
- **同步**：49 个脚本 + 工具 三处一致（服务器/本地/坚果云）**49/49 ✅**

### 2026-09-26 · 批 3：协议头 / 双写 FTS / off-by-one 三类修复 + FTS 对账

#### 3.1 HTTP→HTTPS（8 脚本 / 7 条 URL）
- **判据**：扫全库 1317 条写死的 `http://` URL，逐条实测 http vs https → 只有 **7 条**属「http 死、https 活」（另 548 条 http 正常，**绝不能盲切**，已避开）
- **修法**：按域名精确替换 http→https（共 21 处）+ 备份 `Archive/*.bak_20260925_https` + `py_compile` 8/8
- **实跑**：6/8 见效 —— `anlu` +15 ｜ `jxln` +12 ｜ `xunwu` +38 ｜ `yantai` new8/pushed75 ｜ `xunwu_tzgg` 正常 ｜ `zhcqhj` EXIT=0；`shaowu` 超时（慢非空）；`jxdy` 暴露第二个 bug（见 3.2）
- 兄弟脚本 `crawl_zhcqhj_gsl.py` 一并切片，但实跑 Found 0 articles → 归入「列表抓空」另计

#### 3.2 jxdy_hjypj 双写 FTS（错误 20 → 0）
- **症状**：切 https 后能访问站点，但 20 条全部 `constraint failed`
- **根因**：脚本手写 `INSERT INTO gov_search(rowid,...)`，而 gov_raw 上已有触发器 `trg_gov_raw_fts_ins AFTER INSERT → INSERT OR REPLACE INTO gov_search(rowid,...) VALUES(new.id,...)` → **同一行写两次** → rowid 冲突
- **修法（最小改动）**：`INSERT INTO gov_search` → `INSERT OR REPLACE`；`INSERT INTO gov_raw` → `INSERT OR IGNORE`
- **验证**：EXIT=0 ｜ 列表 20 条 ｜ 新增 0 / 重复 20 / **错误 0**（原来每次 20 个错误）

#### 3.3 shaowu off-by-one（0 秒假成功）
- **症状**：生产 `run_logs` 近 5 次全是 0 秒完成、0 新增、状态"成功"
- **根因**：config `args="1"` → `_MAX_PG=1` → `for pg in range(1, _MAX_PG or 53)` = **`range(1,1)` 空循环** → 连第 1 页都没抓
- **修法**：`range(1, (_MAX_PG or 52) + 1)`（args=1 → 扫第1页；无参 → 仍 53 = 全 52 页，行为不变）
- **验证**：11s 完成、`[PAGE] 第1页` 正常解析、1150 条正确识别为重复

#### 3.4 健康确认（不需动）
- `chiping`：最长 455s / 失败 0/52 → 慢但健康
- `ccs`：config `args=--pages 1` → 只抓第1页 30 条全部已存在 → 0 新增属**正确行为**（此前"597 条 / 300s"是我未带参数全量跑的假象）

#### 3.5 FTS 对账（验证今日修复未留坑）
- 对「批2 涉及的 45 站」+「89 个手写删 FTS 脚本的 52 站」逐站比对 `gov_raw` vs `gov_search`
- **结果**：97 站 / 18,992 行 → **FTS 查不到 0 条** ✅ 无"数据在但搜不到"
- **遗留**：89 脚本的手写 `DELETE FROM gov_search` 无数据损害，但**仍是抢锁源**（`luanxian`/`quanjiao` 60%/53% 失败的同一机制）→ 列为**低优先**防抢锁优化

### 待办（批 3 起）

- `crawl_lufeng.py`：跳过 `javascript:void(0)` 链接（`unknown url type: javascript`）
- `crawl_wenshang_gggs.py`：Playwright 列表未渲染（间歇 50%）
- 4 个「疑似调度器误判」实跑取证：`crawl_longtan_zcfg` / `crawl_nc_hjbha` / `crawl_yjgx` / `crawl_hbqj_eia`
- 3 个非真失败清理（进 D5 定策）：`jd_kfq` / `jd_xnz` / `crawl_yanshou100.py`
- `crawl_ahgc.py`：traceback 显示跑的是 `/mnt/data/crawler/` 旧副本 → 需实跑取证

