这两批改动此前一直压在工作区未提交,本次一并归档。go build ./... 通过。
一、招聘爬虫健壮性
- 新增 internal/service/recruitment/source_config.go:
crawl_source.config(VARCHAR(1000) JSON)的源级抓取参数解析 —— 增量窗口天数、
单次详情页上限、最大翻页数、详情间隔限速、自定义标准词/排除词。
全部字段可选,JSON 解析失败即回退默认值,保证历史数据零迁移可用,
且一个源的脏配置不会拖垮整个调度。
- 新增 internal/service/recruitment/keywords.go(含 keywords_test.go 与 testdata/):
链接筛选由「URL 形态命中 AND 文本语义命中」改为评分制 —— URL 形态加分、
标准词加分、排除词大幅减分,达阈值即入选。原与逻辑会系统性漏抓
「补充工作人员的通知」「公开选调公务员简章」等标题变体,且静默无报错。
- 新增 manifest/sql/recruitment/004_crawl_source_status.sql:
crawl_source 增加「最近一次运行状态」冗余列,抓取结束时写入,
使 Sources() 查询零 JOIN 零扫描 —— 规避原实现全表扫描只增不减的 crawl_log、
随运行时间线性劣化的问题。幂等,可重复执行。
- internal/service/recruitment/crawler.go:在既有「静态两级 / SPA / curl 回退」
流程上做锚点抽取与过滤、编码回退的健壮性增强。
- internal/service/recruitment/bark.go、recruitment.go:配合上述调整。
二、通知记录增强
- api/notice、internal/controller/notice、internal/service/notice、
internal/model/{dto,entity,do}/notice.go:通知日志查询与操作扩展 ——
批次号、状态、重试次数、来源、耗时、详情、删除、清空。
- 新增 internal/model/dto/notice_meta.go(字典选项元数据,供前端筛选器取选项)。
- 新增 manifest/sql/017_notice_log_enhance.sql:notice_log 扩展列 +
删除/清空/详情/字典选项接口权限,幂等(ALTER 走 information_schema 判断,
菜单 ON DUPLICATE KEY UPDATE,角色绑定 INSERT IGNORE)。
三、仓库卫生
- .gitignore 补 rc_*.log 与 rc_verify*,挡掉本地离线验证产物
(含 30MB 的 rc_verify.exe),避免误入库。
设计依据见 docs/recruitment-crawler-design.md。
注:017 与 recruitment/004 两个 SQL 为增量迁移,DB 结构变更不自动 DDL,
生产库需手动导入。
40 lines
1.3 KiB
Go
40 lines
1.3 KiB
Go
package recruitment
|
||
|
||
import (
|
||
"os"
|
||
"testing"
|
||
)
|
||
|
||
// TestLiveAnchorScoring 诊断:读取本地保存的列表页 HTML,打印每个锚点的评分决策。
|
||
// 用于定位「单元测试判定应过滤、但实际抓取却入库」的差异。
|
||
// 运行前需将列表页 HTML 保存到 testdata/rszk.html。
|
||
func TestLiveAnchorScoring(t *testing.T) {
|
||
data, err := os.ReadFile("testdata/rszk.html")
|
||
if err != nil {
|
||
t.Skipf("跳过:未提供 testdata/rszk.html (%v)", err)
|
||
}
|
||
html := string(data)
|
||
cfg := SourceConfig{} // 模拟源1的配置(无 excludeWords 覆盖)
|
||
incWords := cfg.includeWordsOrDefault()
|
||
excWords := cfg.excludeWordsOrDefault()
|
||
minScore := cfg.minScore()
|
||
|
||
t.Logf("词表: include=%d 个, exclude=%d 个, minScore=%d", len(incWords), len(excWords), minScore)
|
||
|
||
base := "http://rsj.guiyang.gov.cn/zfxxgk/fdzdgklm/zfxxgkrsxx/rszk/"
|
||
raw := extractAnchors(html, base)
|
||
t.Logf("原始锚点=%d", len(raw))
|
||
|
||
for i, a := range raw {
|
||
if len([]rune(a.Text)) < 4 {
|
||
continue
|
||
}
|
||
keep := scoreAnchor(a, incWords, excWords, minScore)
|
||
// 仅打印与「依申请公开」或判定为 keep 的条目,聚焦问题。
|
||
if keep || containsAny(a.Text, []string{"依申请公开", "人才网", "信用中国"}) {
|
||
t.Logf("[%d] keep=%v url=%s", i, keep, a.URL)
|
||
t.Logf(" text=%q", a.Text)
|
||
}
|
||
}
|
||
}
|