【免费下载链接】ipblocklist
IP lists full of bad IPs - Updated every 2H
开源项目 ipblocklist 是一个每 2 小时自动聚合更新的 IP 黑名单(inbound/outbound 双列表)项目。更难得的是,它没有引入任何第三方库,仅凭 Python 标准库和两个脚本,就为整条数据管道搭起了完整的数据可观测性:每次运行生成带时间戳的 stats 统计快照,再滚动聚合出每日趋势文件 history.json,让“黑名单规模变化”全程可见。本文带你完整拆解这套 stats 与 history 机制的设计与实现。
为什么 IP 黑名单需要数据可观测性?
ipblocklist 聚合了数十个外部威胁情报源(Spamhaus、blocklist.de、Tor 出口节点等),合并去重后产出两份名单:
| 文件 | 用途 | 当前规模 |
|---|---|---|
| inbound.txt | 入站拦截:恶意扫描、爆破、僵尸网络来源 IP | 约 464 万行 |
| outbound.txt | 出站拦截:C2 服务器、钓鱼站点等恶意目的地 IP | 约 9.2 万行 |
对于这种“数据来自几十家外部源、每 2 小时全量重算”的项目,可观测性回答的是三个关键问题:
- 📊每次更新抓到了多少数据?—— 有没有源悄悄失效、数据断崖下跌?
- ⏱️处理耗时多久?—— 性能是否退化?
- 📈名单总量趋势如何?—— 长期是在增长还是萎缩?
ipblocklist 的答案很朴素:用 JSON 快照 + 每日趋势两个文件,把答案写进仓库。项目 requirements.txt 里只有一行注释:
# No third-party dependencies — stdlib only (urllib, ipaddress, concurrent.futures)也就是说,整条统计链路零第三方依赖,任何有 Python 的环境都能跑。
项目结构:3 个目录 + 2 个脚本看懂全局
ipblocklist/ ├── update_tables.py # 主更新脚本:抓取 → 过滤 → 输出名单 + stats 快照 ├── generate_history.py # 历史脚本:把 stats 快照聚合为 90 天每日趋势 ├── inbound.txt # 最终产出的入站黑名单 ├── outbound.txt # 最终产出的出站黑名单 ├── tables/ │ ├── inbound/ # 入站源清单与中间结果(ipv6.txt、networks.txt、single_ips.txt) │ └── outbound/ └── stats/ ├── stats_YYYYMMDD_HHMMSS.json # 每次更新的统计快照 ├── latest.json # 最近一次更新(永远是最新快照的副本) ├── history.json # 90 天每日趋势 └── archived/ # 历史快照归档(约 2600+ 个文件)数据流向一目了然:
tables/inbound/urltable_inbound(源 URL 清单)→update_tables.py抓取解析 →inbound.txt/outbound.txt+stats/快照 →generate_history.py聚合 →stats/history.json
第一道防线:stats 统计快照的生成机制
一次更新产出 3 类数据文件
核心逻辑在 update_tables.py 的main()中。它先构建一个空的dashboard_data骨架,包含timestamp、execution_duration_seconds、inbound、outbound四个字段:
dashboard_data = { "timestamp": datetime.now(timezone.utc).isoformat(), "execution_duration_seconds": 0, "inbound": {}, "outbound": {} }随后对 inbound/outbound 分别执行“抓取 → 排除 → 输出”,每处理完一条方向就填充对应分支(见 update_tables.py#L544-L566):
dashboard_data["inbound"] = { "sources": inbound_sources, # 每个源 URL 各自贡献的 IP 数量 "raw_total": sum(inbound_sources.values()), "unique_pre_collapse": len(inbound_ips), "stats": inbound_stats # 压缩后的细分统计 }处理完成后,脚本按“时间戳文件 + latest.json”双写模式落盘(update_tables.py#L571-L579):
timestamp_str = datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S') with open(os.path.join(stats_dir, f"stats_{timestamp_str}.json"), 'w') as f: json.dump(dashboard_data, f, indent=4) with open(os.path.join(stats_dir, 'latest.json'), 'w') as f: json.dump(dashboard_data, f, indent=4)| 文件 | 角色 | 特点 |
|---|---|---|
stats/stats_20261022_145311.json | 历史快照 | 文件名自带 UTC 时间戳,每 2 小时新增一个 |
stats/latest.json | 最新快照 | 固定路径,方便仪表盘/监控直接读取,无需 glob |
stats/history.json | 每日趋势 | 由第二个脚本聚合生成 |
这种“快照 + 最新指针”双写是标准库里实现观测数据发布的经典模式:历史数据不可变、最新数据零查找成本。
一份 stats 快照里到底记录了什么?
以 stats/latest.json 为例,一次真实更新的记录包括:
| 字段 | 示例值 | 观测价值 |
|---|---|---|
timestamp | 2026-10-22T14:43:11+00:00 | 更新时刻(UTC) |
execution_duration_seconds | 600.79 | 本轮耗时,性能退化一眼可见 |
inbound.sources | 约 90 个 URL → 各自条数 | 最细粒度:定位哪个源贡献多少 |
inbound.raw_total | 9108192 | 原始抓到的总条数 |
inbound.unique_pre_collapse | 4646862 | 去重排除后的唯一网络数 |
inbound.stats.total_optimized_count | 4646862 | 最终优化输出的条目数 |
inbound.stats.top_metrics.total_ipv4_addresses_covered | 20356785 | 覆盖的 IPv4 地址总数 |
inbound.stats.top_metrics.cidr_distribution | {"32": 4381371, "24": 1035, ...} | 按前缀长度分布,反映名单“粒度”结构 |
其中sources字段最有排查价值:inbound.sources中每个源都记了独立条数,例如某源突然从数万条变成0(快照里确实存在"https://www.darklist.de/raw.php": 0这样的记录),就意味着该源失效,运维可以立即告警——这就是“源级数据质量监控”。
top_metrics则在 write_files() 中顺手计算:遍历压缩后的 IPv4 网络,累加num_addresses得到覆盖地址总数,并按prefixlen分桶得到 CIDR 分布,几乎零额外成本。
第二道防线:history 历史趋势的生成机制
90 天窗口 + 每日采样
generate_history.py 是一个可以独立运行的小脚本,generate_history()的文档注释写得很直白(generate_history.py#L20-L30):
Parses stats json files to generate a history of total_ipv4_addresses_covered for the last 3 months. Only keeps one entry (the latest) per day in the output JSON.
它的核心规则有三条:
- 扫描范围:同时扫
stats/和stats/archived/两个目录,保证趋势完整; - 90 天窗口:
cutoff_date = datetime.now() - timedelta(days=90),早于截止日期的文件直接跳过(generate_history.py#L35); - 每日只留一条:以
YYYY-MM-DD为键写入daily_records字典,同一天的多次更新(每天约 12 次)后写的自然覆盖先写的,最终每天只保留最新一次快照的值。
提取的指标由extract_ipv4_covered()完成——把 inbound 与 outbound 的total_ipv4_addresses_covered相加(generate_history.py#L10-L17),并对 JSON 缺失做了try/except容错,坏文件只会打一条 Warning 而不会中断整个任务。
最终产出的 stats/history.json 是一个按日期排序的数组,每个元素只有 3 个字段:
{ "date": "2026-07-24T22:55:47", "timestamp": 1784933747.0, "total_ipv4_addresses_covered": 23921068 }目前文件里已有约 90 天、440 行的记录,数值从 7 月底的 2392 万缓慢增长到 10 月下旬的 2422 万——这条曲线就是整个黑名单项目的“生命线指标”,任何断崖或异常跳变都会在图上无所遁形。
自动归档:让 stats 目录永远保持轻量
generate_history.py还有一个容易被忽略的职责——归档。它把stats/根目录下所有stats_开头的快照移动到stats/archived/(generate_history.py#L93-L100):
for filepath in files_to_archive: try: shutil.move(filepath, archive_dir) except Exception as e: print(f"Error moving {os.path.basename(filepath)}: {e}")这带来了两个好处:
- ✅目录干净:
stats/根目录任意时刻只有最近一个周期(3 个左右)的快照 +latest.json+history.json,仓库浏览体验很好; - ✅历史不丢:
archived/下已积累约 2600 个文件(每 2 小时一个 × 数周),趋势重建永远有据可查,单文件归档失败也只是打印错误而不影响其他文件。
值得注意的小细节:归档逻辑用shutil.move而非重命名,且对latest.json/history.json显式排除(ignored_files集合),避免把“指针文件”当数据文件处理。
快速上手:本地复现整套统计机制
由于零第三方依赖,复现整套 stats/history 流程只需要标准库。如果希望 clone 仓库:
git clone https://gitcode.com/gh_mirrors/ip/ipblocklist cd ipblocklist| 步骤 | 命令 | 产物 |
|---|---|---|
| 1. 执行全量更新 | python update_tables.py | 更新 inbound.txt、outbound.txt,新增stats/stats_*.json并刷新 stats/latest.json |
| 2. 生成每日趋势 | python generate_history.py | 重建 stats/history.json,旧快照移入stats/archived/ |
| 3. 调试排查 | python update_tables.py --debug | 输出 DEBUG 级日志;加--no-mp可关闭多进程便于断点 |
💡 说明:完整跑一次需要遍历几十家外部数据源并做大规模并集/排除计算(参考
latest.json,官方单次约 10 分钟),本地体验建议直接阅读仓库中已生成的stats/文件来理解数据形态。
关键启示:标准库也能做出专业的数据可观测性
回顾 ipblocklist 的 stats 与 history 机制,可以提炼出 4 条可直接搬走的实践:
- 观测数据与业务数据同仓:统计快照直接随代码仓库提交,无需额外存储设施,
git log天然就是数据变更审计日志; - “时间戳快照 + latest.json 指针”双写:历史不可变、最新零成本读取,监控和仪表盘各取所需;
- 源级明细是排查的命脉:
sources字段让“哪个数据源坏了”从猜谜变成查表; - 趋势与明细分层:
stats_*.json存全量细节(可按需归档),history.json只存每日单值,兼顾回溯深度与读取轻量。
整套机制只用了json、os、glob、shutil、datetime、concurrent.futures、ipaddress、urllib这些标准库模块,证明了数据可观测性不需要昂贵的技术栈——清晰的指标定义 + 可靠的落盘纪律,才是可观测性的核心。
【免费下载链接】ipblocklist
IP lists full of bad IPs - Updated every 2H
相关推荐
Headroom 可观测性实战:/stats、/stats-history、Prometheus 与 OTEL 指标体系详解
Headroom 可观测性实战:/stats、/stats history、Prometheus 与 OTEL 指标体系详解 Headroom 把“省了多少 t
人工智能大模型LLM网关AI Agent终极指南:如何使用Nightingale与OpenTelemetry构建统一可观测性平台
终极指南:如何使用Nightingale与OpenTelemetry构建统一可观测性平台 Nightingale作为一款集成Prometheus和Grafana
后端可观测性指标监控告警AI AgentPython 标准库 xmlrpc.server 详解:用 SimpleXMLRPCServer 与 CGIXMLRPCRequestHandler 搭建 XML-RPC 服务
Python 标准库 xmlrpc.server 详解:用 SimpleXMLRPCServer 与 CGIXMLRPCRequestHandler 搭建 XM
编程语言语言运行时标准库解释器
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考