# bangwen-collectors 边缘采集系统 🕷️ > **专为招考数据聚合设计的高性能、免代码声明式与 SSRF 安全强化的边缘抓取体系。** --- ## 📖 目录 - [✨ 概述](#-概述) - [📁 目录结构](#-目录结构) - [🚀 快速开始](#-快速开始) - [环境准备](#环境准备) - [本地安装](#本地安装) - [🛠️ 采集器配置与开发指南](#️-采集器配置与开发指南) - [免代码声明式 TOML 站点卡片](#免代码声明式-toml-站点卡片) - [复杂场景 Python 定制适配器](#复杂场景-python-定制适配器) - [⚙️ 调度策略与频控机制](#️-调度策略与频控机制) - [🧪 测试与验证](#-测试与验证) - [📜 开源协议](#-开源协议) --- ## ✨ 概述 `bangwen-collectors` 作为 `bangwen` 招考数据中枢的分布式边缘抽取层: - **双模自动发现**:同时支持零代码声明式 TOML 站点配置卡片(`sources/`)与 Python 定制适配器(`adapters/`)。 - **按域名分组并发**:对不同域名并发抓取,而对相同域名严格排队串行,保障采集效率的同时彻底杜绝政务网 WAF 封锁。 - **礼貌延时与节流**:栏目间保持静默等待(默认 3.0s),单篇详情提取保留 0.3s 间隔微节流。 - **全链路 SSRF 纵深防护**:底层内置私有内网 IP 阻断、严格域名白名单匹配与 HTTP 重定向逐跳安全性校验。 --- ## 📁 目录结构 ``` collectors/ ├── adapters/ # 针对复杂动态站点的 Python 专属抓取适配器 │ └── sc/chengdu_rsks.py # 成都人事考试网抓取适配器 ├── sources/ # 零代码声明式 TOML 站点配置卡片 │ ├── sc/ # 四川省站点(如绵阳人事考试网、自贡人事考试网) │ └── yn/ # 云南省站点(如云南人社厅、玉溪市人民政府) ├── common/ # 核心通用组件 │ ├── content.py # 脏正文清洗、超长文本截断与反爬标记识别 │ ├── declarative.py # 通用免代码声明式解析执行引擎 │ ├── fetcher.py # 支持 SSRF 逐跳校验与限速的 PoliteFetcher 客户端 │ ├── protocol.py # 与 bangwen/v1 摄入协议严格对齐的 Pydantic 模型 │ └── security.py # URL 白名单判定与内网 IP 阻断工具 ├── tests/ # 安全防护与内容清洗回归测试集 ├── config.toml # 采集调度与省份过滤总配置文件 ├── runner.py # 多域名调度器与常驻运行入口 └── Dockerfile # 专属非 root 用户(UID 10001)容器镜像定义 ``` --- ## 🚀 快速开始 ### 环境准备 - Python 3.12+ - [uv](https://docs.astral.sh/uv/) 包管理器 ### 本地安装 1. **安装依赖**: ```bash uv sync ``` 2. **列出当前注册的所有采集渠道**: ```bash uv run python runner.py --list ``` 3. **执行一轮即时抓取与推流**: ```bash uv run python runner.py --once ``` --- ## 🛠️ 采集器配置与开发指南 ### 免代码声明式 TOML 站点卡片 对于标准 HTML 结构的政务招考网站,只需在 `sources/{province}/{site_id}.toml` 编写配置,无需编写任何代码: ```toml [site] id = "yn.yuxi" name = "玉溪市人民政府" province = "云南省" city = "玉溪市" employer = "玉溪市相关用人单位" employer_type = "事业单位" allowed_domains = ["yuxi.gov.cn", "yxrc.cn"] [template] item_selector = "div.news-list a" url_pattern = "/article/\\d+\\.html" title_selector = "h1.article-title" body_selector = "div.article-content" date_regex = "(\\d{4}[-/年]\\d{1,2}[-/月]\\d{1,2})" attachment_extensions = [".xlsx", ".xls", ".pdf", ".docx", ".doc", ".zip"] [[channels]] id = "rszk" name = "人事招考" start_url = "https://www.yuxi.gov.cn/rszk.html" keywords = ["招聘", "考试", "录用", "公示"] ``` ### 复杂场景 Python 定制适配器 对于含有复杂会话保持、加密参数或动态分页的站点,在 `adapters/{province}/{name}.py` 编写 Python 适配器: - 实现抓取函数并返回符合标准的 `IngestPayload`。 - 强制使用 `common.security.is_safe_url` 实施外链与重定向安全隔离。 - 提取正文时使用 `common.content.sanitize_body_text` 剥离导航与脏文本。 --- ## ⚙️ 调度策略与频控机制 调度器(`runner.py`)提供细粒度的运行控制: | 环境变量 / 命令行参数 | 默认值 | 说明 | |-----------------------|--------|------| | `CORE_INGEST_URL` | `http://core:8080/api/v1/ingest` | Rust 核心网关的摄入接口地址 | | `INGEST_TOKEN` | *空* | 与内核对齐的 HTTP Bearer 认证 Token | | `SCHEDULE_INTERVAL_HOURS` | `6` | 常驻巡检的周期时间(小时) | | `--provinces` | `[]` | 目标省份过滤(例如 `yn,sc`) | | `--concurrency` | `3` | 跨域名的最大并发数 | --- ## 🧪 测试与验证 运行完备的本地安全回归套件(涵盖 SSRF 私网阻断、反爬脏正文过滤与附件扩展名判定): ```bash uv run python tests/test_content_and_security.py # 预期输出: All security and content tests passed! ``` --- ## 📜 开源协议 本项目采用 [MIT](../LICENSE) 开源协议。

(回到顶部)