---
title: "00-parsegpt"
created: 2026-04-02
tags:
- 项目
aliases:
- parsegpt
---
# parsegpt
> 这是一套**校招/社招公告的全链路解析系统**,把爬取到的原始 HTML 页面转化为结构化 JSON,供后续搜索、展示、推荐使用。整体由五个模块分工协作,有一条明确的主干流程,也有两条独立的分支路径。
![[image-42313e76.png]]
### [[06-html_to_text|html_to_text]] — 底层 HTML 清洗
最底层的工具,被多个上层模块调用。核心逻辑是把 HTML 转成干净的纯文本,但它对 `
` 有特殊处理——不是简单地 `get_text()`,而是把多列单元格按行合并,尽量保留表格的语义结构(比如"岗位名称 / 工作地点 / 招聘人数"这种横向排列的信息不会丢失)。同时清理掉 CSS、JS、隐藏元素、多余空白和 ` ` 等噪音字符。
### [[01-ann_img|ann_img]] — 图片处理与 OCR
处理公告里嵌入的图片,流程分五层:
1. 下载图片,计算 MD5 和感知哈希(`average_hash`),用于内容去重和黑名单匹配
2. 二维码检测(`detect_qr_code`):识别是否是纯二维码(`Y`)、混合图(`H`)还是普通图(`N`)
3. 对非纯二维码图片做 PaddleOCR 文字识别,提取出文字供后续搜索全文使用
4. 多层过滤:按尺寸、透明度、OCR 文字量、MD5 黑名单、相似哈希黑名单、学校 Banner 黑词表等条件剔除无效图片
5. 把有效图片上传华为云 OBS,替换 HTML 里原来的 `src` 地址
关键设计:对混合图(既有普通内容又有二维码),会把二维码区域裁切出来单独上传,便于前端展示"扫码投递"入口。
### [[02-ann_md|ann_md]] — HTML 预处理与 Markdown 转换
流水线的第一道关卡,处理完成后才把内容交给大模型。主要做六件事:
**① 清除噪音 DOM**(`fix_html_div`):按渠道配置(`detail_rm_classes` / `detail_rm_ids`)删除导航栏、页脚、广告等无关 div。还支持按出现顺序删除特定 div(用 `^` 符号标记"第 N 个")。
**② 修复链接和图片路径**(`fix_html_a` / `fix_html_img_src`):相对路径统一补全为绝对 URL,Base64 内嵌图片先保存本地再上传 OBS 变成外链。
**③ 提取硬编码的结构化字段**(`find_hardcode_tag`):有些网站的公司名、公告标题藏在固定 CSS 类里,直接选择器抓取,不依赖大模型。还支持从完整页面(`.full` 文件)中提取大模型视角里看不到的字段。
**④ 调用** `ann_img.py` 完成图片的下载、OCR、二维码检测、上传替换。
**⑤ HTML 转 Markdown**(`html2md_table`):检测表格是否有合并单元格(`colspan` / `rowspan`),没有则用专用工具转换,有则退化到 `html2text` 库处理。
**⑥ 渠道专项修复**(`common_process_sch_98534`):针对某所合作学校(编号 98534)的 Markdown 岗位信息区块格式做正则定制处理,是写死的特殊逻辑。
### [[03-ann_model|ann_model]] — 核心调度器(主入口)
整个系统的大脑,串联所有模块,分三个阶段处理。
#### **第一阶段:公告级解析**
把 Markdown 全文用 `get_template_campus` 模板调用大模型,提取公司名、应聘方式、毕业年届、公告类型等字段,然后做一系列后处理:
- 过期检测:截止日期超过 1 个月直接丢弃
- 多公司检测:大模型判断是多家公司联合发布时,将公司名改为"校招公告",避免归属混乱
- 三无过滤:无投递链接 + 无应聘文本 + 无邮箱 + 无联系方式的公告直接丢弃
- 云端去重:调用 `check_cloud` API 与已入库数据比对
- 毕业届修复(`fix_graduate_year`):用正则从标题提取,支持"25届"、"2026"等多种写法,实在提取不到则默认当前年(8月后自动+1年)
**关键分叉:**
如果渠道在白名单学校内,且大模型判断公告类型为"职位",则走 `ann_model_job.py` 的单职位路径;否则走普通公告路径。
#### **第二阶段:职位列表解析**(普通公告路径)
用 `get_template_job` 模板调用大模型,从全文提取所有职位列表(一个公告可能含几十个职位)。做学历规范化(`fix_diploma`)、去重、空职位名过滤等修复。如果主文本没提取到职位,还会从 `tuning_content`(页面特定区域抓取的补充内容)里再试一次。
#### **第三阶段:Markdown 格式处理**
根据页面特征分四种策略:
- 大图文章(微信长图文)/ 普通页面 → 读本地 md 文件,用豆包大模型润色格式
- 外部链接页面 → 用大模型从全文直接提取 Markdown
- 含复杂表格的页面 → 用大模型专门处理表格转 Markdown
最终把 `ann`(公告信息)+ `jobs`(职位列表)+ `other`(元数据)+ `mdfile`(展示用 Markdown)四个节点写入 JSON 模型文件。
### [[04-ann_model_job|ann_model_job]] vs [[05-cjob_model|cjob_model]] — 两条单职位解析路径
这两个文件都是处理"一个页面对应一个职位"的场景,但来源和复杂度不同:
`ann_model_job.py` 处理**公告内的单职位**(由 `ann_model.py` 分支调用)。流程相对简单:HTML 转纯文本 → Qwen 大模型提取 → 校验质量 → 与公告元数据合并(公司名、链接、申请方式、联系人等)→ 写入 JSON。
`cjob_model.py` 处理**大公司招聘网站的职位详情页**(独立入口,不经过 `ann_model.py`)。复杂得多:
- 通过 `detail_selector` 配置的 CSS 选择器精准定位职位正文区域,支持正则备选方案
- 从页面 Header 区域额外提取职位类别、工作地点、发布时间、招聘人数(通过 `detail_hd` 配置项区分不同网站的 DOM 结构)
- 对职位类型做规范化:`hd_hopeworktype` 字段决定 `DocType` 取值(`shixi` / `xiaozhao` / `shezhao`)
- 使用带 system prompt 的 `new_call_gpt` 接口,而非普通补全接口
---
**项目分区导航**:[[04-spider_sch.py|spider_sch.py]] ⬅️ | 00-parsegpt | ➡️ [[01-ann_img|ann_img]]