全链路流程梳理:招聘数据自动化抓取

一、系统全景架构

image-62607bc7

二、启动阶段(定时任务 → 配置加载)

2.1 定时任务脚本

@echo off
echo 正在启动中...
call E:\chu\python310_ve\Scripts\activate.bat    ← 激活 Python 3.10 虚拟环境
cd /d E:\chu\qzclawler                           ← 切换工作目录
git pull                                          ← 拉取最新代码和配置
python main.py -m cp -f 51                        ← 启动主程序

三步保障

  1. 环境隔离:虚拟环境保证 PaddleOCR、Playwright 等依赖版本正确
  2. 代码同步:git pull 确保 .ini 配置和爬虫代码是最新的
  3. 分片执行-f 51 只负责第 51 号配置文件里的公司,与 -f 01-f 50 并行互不干扰

2.2 参数解析与实例化

python main.py -m cp -f 51
                    │          │      │
                    │          │      └─ 拼接为 setting_com_51.ini
                    │          └─ cp = Company 模式,调用 SpiderCom
                    └─ 主程序入口

实例化三个类:
  s  = SpiderSch(51)    ← 学校爬虫(本次未使用)
  cs = SpiderCom(51)    ← 公司爬虫(本次主角)
  d  = SpiderData(s)    ← 数据处理器

2.3 配置文件结构(setting_com_51.ini)

[com_00075]                          ← 松山湖材料实验室
com_name = 松山湖材料实验室
com_logo = https://xxx/logo.png
urls = {"xiaozhao": "https://...", "shezhao": "https://...", "overseas": "https://..."}
template = template_01005
func_name = gen_00005_3
json_domain =
hd_all_location = {"深圳": "深圳", "东莞": "东莞"}

[com_00498]                          ← 四三九九网络
com_name = 四三九九网络股份有限公司
urls = {"shezhao": "https://...", "xiaozhao": "https://..."}
template = template_50150
json_domain = wx-hr.img4399.com      ← 模拟微信端请求获取JSON
func_name = gen_50150

[com_00499]                          ← 科捷智能(飞书招聘ATS)
com_name = 科捷智能科技股份有限公司
urls = {"shezhao": "https://...feishu..."}
template = template_50151

每个公司节点包含的关键字段

字段 作用
com_name / com_webname 公司全称 / 前端展示名
com_logo Logo 图片链接
urls 按招聘类型分类的 URL(shezhao/xiaozhao/shixi)
pre_open_url 预加载链接,用于获取 Cookie/Token
template HTML/JSON 解析模板编号
func_name 自定义解析函数名(gen_xxxxx)
json_domain API 接口域名(前后端分离网站)
hd_all_location 城市映射字典
max_parent_level 爬虫钻取层级控制
click_type 模拟点击方式

三、数据抓取阶段(四种抓取策略)

3.1 通用 HTML 抓取(大多数公司)

spider_com.py
    │
    ├─ get_page_data()
    │   用 Playwright 打开列表页
    │   根据 template 找到所有职位链接
    │
    ├─ get_page_detail_data()
    │   循环遍历每个职位链接
    │
    └─ get_page_detail_content()
        打开详情页 → 提取 JD 文本
        写入 detail_xxx.html

自动化解析函数体系(auto_gen / auto_gen_com)

爬取到页面 HTML
    │
    ▼
func_call.py → 动态加载 gen_000xx.py → extract_table_from_html()
    │
    ├─ 成功 → 输出 JSON(职位名/时间/链接/部门/地点/薪资)
    │
    └─ 结果为空
          │
          ▼
    func_gen_bygpt.py → 调用 GPT-4o
          │
          └─ 自动生成新的 gen_func_code_xxx_tmp.py
               人工审核后重命名为正式文件

三类文件分工(auto_gen_com 目录):

文件类型 作用 示例
gen_000xx.py 职位列表 HTML 解析 提取职位名、部门、地点、薪资
click_500xx.py Tab 点击切换 点击"博士生招聘"筛选标签
page_000xx.py 翻页控制 点击"下一页",检测 disabled 判断末页

3.2 API 直连抓取(auto_api)

baidu_data_proc_api.py (总入口路由)
    │
    ├─ com_90001 百度 ─── POST 招聘 API + 代理池(getProxy,递归重试3次)
    │                     爬取间隔 30秒,详情页用 requests 拉取
    │
    ├─ com_90002 软通动力 ── POST 两套 API(社招/校招格式不同,自动适配)
    │                        详情页用 Playwright 渲染(SPA)+ ThreadPoolExecutor
    │                        爬取间隔 1秒
    │
    ├─ com_90003 京东 ──── POST 招聘 API
    │
    ├─ com_90004 金蝶 ──── 下载 jobs.js 静态文件,正则提取 JSON
    │
    └─ com_90005 中国人保 ── POST 招聘 API

统一落盘逻辑

获取到职位列表 JSON
    │
    ├─ 文件已存在?→ 只更新 mtime(标记"本次爬到了"),跳过
    │
    ├─ transform_job_json → 私有字段名 → 系统统一字段名
    │   写入 detail_xxx.json
    │
    ├─ 获取/生成 HTML 文件
    │   百度:requests 拉详情页
    │   软通:Playwright 渲染保存
    │   金蝶:generate_html 拼接伪 HTML
    │
    └─ detail_xxx.html + detail_xxx.json 落盘

文件名策略hashlib.md5(url.encode()).hexdigest() → 同一 URL 永远映射同一文件,天然去重

3.3 网络响应拦截(auto_on_response)

针对前后端分离 SPA,HTML 里没有职位数据的场景:

main_proc.py → 按 _key 路由
    │
    └─ com_91000 兴业银行 → xingye_proc.py
         │
         ├─ 第一层 xingye_proc:
         │   page.on('response', handler) 注册拦截器
         │   打开招聘页 → 循环点击"下一页"(默认3页 / cp_full全量100页)
         │   每次翻页等待 30秒
         │
         ├─ 第二层 response_handler:
         │   过滤目标 API 响应(job.cib.com.cn/ersApi/...)
         │   确认 message=='成功' → 遍历职位列表
         │
         └─ 第三层 xingye_json:
              原始字段 → 统一字段格式
              generate_html → 拼成伪 HTML → 进入后续流水线

3.4 四种策略对比

通用HTML抓取          API直连            响应拦截           JS文件解析
(大多数公司)        (百度/京东/软通)     (兴业银行)          (金蝶)
     │                  │                  │                  │
 Playwright          requests           Playwright         requests
 渲染页面           POST接口          注册监听器          下载JS文件
     │                  │                  │                  │
 gen_xxx.py         直接拿JSON       handler捕获         正则提取
 解析HTML                              API响应             JSON
     │                  │                  │                  │
     └──────────────────┴──────────────────┴──────────────────┘
                              │
                    统一输出 .html + .json
                              │
                    进入数据解析流水线

四、数据解析流水线(parsegpt)

4.1 总体流程

原始 HTML 文件
    │
    ▼
┌── ann_md.py ──────────────────────────────┐
│  ① 清除噪音 DOM(导航栏/页脚/广告)        │
│  ② 修复链接和图片路径(相对→绝对URL)       │
│  ③ 提取硬编码字段(CSS选择器直接抓取)       │
│  ④ 图片处理(ann_img.py)                  │
│  ⑤ HTML → Markdown 转换                   │
│  ⑥ 渠道专项修复                            │
└──────────────────┬────────────────────────┘
                   │
                   ▼
┌── ann_model.py ──────────────────────────────────────────┐
│  第一阶段:公告级解析                                      │
│    大模型提取公司名/应聘方式/毕业届/公告类型                  │
│    → 过期检测 → 多公司检测 → 三无过滤 → 云端去重            │
│    → 毕业届修复                                           │
│                                                          │
│  ┌─ 分叉判断 ────────────────────────────────┐            │
│  │ 白名单学校 + 类型="职位"                    │            │
│  │    → ann_model_job.py(单职位路径)         │            │
│  │ 否则                                      │            │
│  │    → 第二阶段:职位列表解析(多职位提取)     │            │
│  └───────────────────────────────────────────┘            │
│                                                          │
│  第三阶段:Markdown 格式处理                                │
│    大图文章 → 豆包润色                                     │
│    外部链接 → 大模型提取                                    │
│    复杂表格 → 大模型专项处理                                │
│                                                          │
│  输出:ann + jobs + other + mdfile → JSON 模型文件         │
└──────────────────────────────────────────────────────────┘

4.2 ann_md.py — HTML 预处理(6 步)

① fix_html_div      按配置删除无关 div(导航/页脚/广告)
                     支持 ^ 语法标记"第N个"div

② fix_html_a        相对路径 → 绝对 URL
   fix_html_img_src  Base64 内嵌图 → 保存本地 → 上传 OBS → 外链

③ find_hardcode_tag  CSS 选择器直接抓取公司名/标题
                     支持从 .full 文件提取补充字段

④ ann_img.py 调用    图片下载 → MD5/感知哈希去重
                     → 二维码检测(Y纯码/H混合/N普通)
                     → PaddleOCR 文字识别
                     → 多层过滤(尺寸/透明度/黑名单)
                     → 上传华为云 OBS 替换 src

⑤ html2md_table      检测合并单元格(colspan/rowspan)
                     无 → 专用工具转换
                     有 → html2text 库兜底

⑥ common_process_sch_98534   渠道专项修复(定制正则)

4.3 ann_model.py — 三阶段核心调度

第一阶段:公告级解析

Markdown 全文 → get_template_campus 模板 → 大模型
    │
    ├─ 提取:公司名 / 应聘方式 / 毕业届 / 公告类型
    │
    ├─ 过期检测:截止日期超1个月 → 丢弃
    ├─ 多公司检测:联合发布 → 公司名改为"校招公告"
    ├─ 三无过滤:无链接+无文本+无邮箱+无联系方式 → 丢弃
    ├─ 云端去重:check_cloud API 比对
    │   返回码:301过期 / 302黑名单 / 303全文重复 / 304链接重复
    └─ 毕业届修复:正则提取"25届"/"2026" → 默认当前年(8月后+1)

关键分叉

白名单学校 + 公告类型="职位"
    │                         │
    ▼                         ▼
ann_model_job.py          第二阶段:普通公告路径
(单职位解析)             get_template_job → 大模型
                          提取所有职位列表
                          学历规范化 / 去重 / 空职位名过滤
                          主文本无结果 → tuning_content 补充提取

第三阶段:Markdown 格式处理

四种策略:
├─ 大图文章(微信长图文)→ 读本地 md + 豆包润色
├─ 普通页面            → 读本地 md + 豆包润色
├─ 外部链接页面        → 大模型从全文提取 Markdown
└─ 含复杂表格          → 大模型专项处理表格

最终输出 JSON:
{
  "ann":    { 公告信息 },
  "jobs":   [ 职位列表 ],
  "other":  { 元数据 },
  "mdfile": "展示用 Markdown"
}

4.4 两条单职位解析路径对比

维度 ann_model_job.py cjob_model.py
来源 公告内的单职位(ann_model 分支调用) 大公司招聘网站职位详情页(独立入口)
定位方式 HTML 转纯文本直接处理 detail_selector CSS 选择器精准定位
额外字段 与公告元数据合并(公司名/链接/联系人) 从 Header 区域提取类别/地点/时间/人数
职位类型 继承公告类型 hd_hopeworktype 决定(shixi/xiaozhao/shezhao)
模型调用 Qwen 普通补全 带 system prompt 的 new_call_gpt
复杂度 简单 复杂(多层备选方案、正则兜底)

五、AI 模型调用层(api 目录)

5.1 多模型分工

┌─────────────────────────────────────────────────────┐
│                   大模型调用矩阵                      │
├─────────────┬───────────────────────────────────────┤
│ 豆包(字节)   │ 核心模块,处理职位信息(cjob)            │
│ doubao_api   │ 提取 20-30 个精细字段                  │
│              │ 亮点:Prompt Caching(70h过期)         │
│              │ Token 精细统计(input/cache/output)    │
├─────────────┼───────────────────────────────────────┤
│ Azure OpenAI │ 处理招聘公告(ann)                      │
│ openai4o_api │ 提取公司信息/网申时间/岗位列表/投递规则   │
│              │ 保留新旧两版SDK                        │
├─────────────┼───────────────────────────────────────┤
│ 通义千问      │ 备用模型 / 单职位解析                   │
│ qwen_api     │ OpenAI 兼容调用方式                    │
├─────────────┼───────────────────────────────────────┤
│ DeepSeek     │ 备用模型 / 实验性接口                   │
│ deepseek_api │ OpenAI 兼容调用方式                    │
└─────────────┴───────────────────────────────────────┘

5.2 OCR 模块(ocr_api.py)

输入图片
    │
    ├─ GIF → 转取第一帧
    │
    ├─ 超长图片?
    │   └─ img_cut 智能切图算法
    │       OpenCV connectedComponents 连通组件检测
    │       切线碰到文字 → 智能上移,保证文字完整性
    │
    └─ PaddleOCR 识别 → 输出文字

5.3 存储与同步

hwcloud_api.py (华为云 OBS)
    │
    └─ 上传图片/文档 → quanfile 桶 → 返回公共 URL

quanzhi_api.py (业务系统)
    │
    ├─ fix_upload_cloud:日期格式校验修复
    │
    ├─ check_cloud:入库前拦截
    │   301 = 公告过期
    │   302 = 包含黑名单
    │   303 = 全文重复
    │   304 = 链接重复
    │
    └─ ann_add:POST 结构化 JSON → 121.36.63.42

六、完整数据流(端到端)

Windows 定时任务
    │
    ▼
① git pull 同步代码
② activate.bat 激活环境
③ python main.py -m cp -f 51
    │
    ▼
④ 读取 setting_com_51.ini(松山湖/4399/科捷智能...)
    │
    ▼
⑤ 遍历每个公司,选择抓取策略:
    ├─ 通用HTML → Playwright + gen_xxx.py 解析
    ├─ API直连  → requests POST 接口
    ├─ 响应拦截  → Playwright page.on('response')
    └─ JS文件   → 正则提取 JSON
    │
    ▼
⑥ 统一输出 detail_xxx.html + detail_xxx.json
    │
    ▼
⑦ ann_md.py:HTML清洗 → 图片处理(OCR/去重/上传OBS) → Markdown转换
    │
    ▼
⑧ ann_model.py:大模型结构化提取
    ├─ 公告级解析(过期/多公司/三无/去重)
    ├─ 职位列表解析 或 单职位解析
    └─ Markdown 格式化
    │
    ▼
⑨ quanzhi_api.py:
    ├─ check_cloud 云端去重(301/302/303/304)
    ├─ fix_upload_cloud 日期修复
    └─ ann_add POST → 121.36.63.42 正式数据库
    │
    ▼
⑩ 数据入库完成,供前端搜索/展示/推荐使用

项目分区导航链路追踪 ⬅️ | 02-全链路流程梳理 | ➡️ main.py