全国行政区划边界数据源怎么选?天地图+民政部+OSM 三大来源与村级 GeoJSON 数据获取
做全国行政区划边界数据,最难的从来不是画图,而是「这数据到底哪来的、还新不新」。我刚入行时是打开个能下载的站,看着文件里县界都对、乡镇也在,就直接当成品用,结果做行政区划代码比对时,发现同一个县的边界和民政部当年发布的代码对不上——不是代码错了,是数据源老了四年。那次之后,我做任何 GeoJSON下载 项目的第一问都变成:这个源的上次更新在哪天?
这篇就把我这些年摸出来的数据源层级、村级 GeoJSON 为什么难搞、以及怎么把它串进一条持续的更新流水线讲清楚。属于「全国省市区县区划边界数据下载」这条链路里被低估的一环。
数据源优先级:民政部代码 + 天地图边界 + OSM 兜底
一级管「名分」、一级管「形状」、一级管「兜底」,三者叠加才是准的。我的默认顺序是这样:
| 层级 | 数据源 | 管什么 | 更新节奏 |
|---|---|---|---|
| L0 权威 | 国家民政部区划代码公告 | adcode 与名称的权威增删改 | 每年不定期公告 |
| L1 形状 | 天地图行政区划数据 | 省/市/区县边界几何 | 随影像更新 |
| L2 兜底 | OpenStreetMap / 地方发布 | 缺失区县、乡镇村代码补充 | 持续 |
优先级这么排的原因很简单:adcode 是「唯一主键」,必须以民政部公告为准,因为它决定了你和统计局、公安、邮政的代码体系能不能对上。边界几何则以天地图这类国内官方底图为准——坐标系和国内习惯天然对齐,省去 WGS84 加偏的麻烦。如果某个区县在天地图上是空的,再用 OSM 或该县官方发布的乡镇界去补。这里有个红线别碰:涉及国界的等号边界,永远以官方发布为准,本文只谈纯技术数据整合,不做任何主权层面的改动。
村级 GeoJSON 为什么难:不是数据少,是「口子没开」
说起「全国村级geojson数据下载」,很多人一搜发现网上村级数据为零散发布,就以为源头没有。其实村一级的边界每省都有,只是呈现方式不一样:有的藏在国土空间规划的专题图里,有的作为统计用 12 位代码的附图存在,更多地方只给了「村名 + 中心点」,没有闭合多边形。
做村级数据,核心是拼而不是「下」。我的做法是先拿乡镇级多边形作底,再用该省民政厅历年「乡镇撤并村」批文、以及统计部门发布的村级代码表,把村界的点/线拼回闭合面。拼没拼对,用最土的办法验证:村的面积之和,应当约等于所属乡镇面积,误差超过 5% 就要回头查是不是漏了「村改居」这一类。
// 用 12 位统计用代码 + 乡镇多边形,核对村级面是否拼满
const fs = require('fs');
const { fixCoords } = require('./rewind.js'); // 先统一环方向
const villages = JSON.parse(fs.readFileSync('village.geojson', 'utf8'));
const town = JSON.parse(fs.readFileSync('town.geojson', 'utf8'));
function area(gj) { // 简化等积测算(仅用于核对)
let s = 0;
for (const f of gj.features) {
const r = f.geometry && f.geometry.coordinates[0] || [];
for (let i = 0; i < r.length - 1; i++) {
s += (r[i][0]) * (r[i + 1][1]) - (r[i + 1][0]) * (r[i][1]);
}
}
return Math.abs(s) / 2;
}
const ratio = area(villages) / area(town);
console.log(`村级面占乡镇面比例: ${(ratio * 100).toFixed(1)}%`);
if (ratio < 0.95) console.log('疑似缺村,核对村改居与撤并村批文');
这套「面积回填核对」我每次补一个县都会跑一遍,替我省掉至少三次肉眼找漏洞的返工。
把更新串成流水线:版本 + 校验 + 发布
数据源会动,靠手动记「我上次下到哪版」必翻车。我现在的串法是三位一体:
1. 版本号进文件名。geojsoncn-区县-510722-2026Q2.geojson,绝不写死 latest——静态站更新覆盖同一路径,用户浏览器缓存会一直给旧版,坑过我好几次。 2. sha256 校验和随文件。源更新后算一遍和,比对上一个版本,变了才动发布。这个细节来自「全国省市区县geojson数据下载」里的下载一致性问题——传输环节偶尔丢字节,没校验分不清是源变了还是链路坏了。 3. 发布走静态侧。边界文件烤进静态站点,前端预览免费看,导出成 GeoJSON/PNG 走 ¥1.99/次的付费项。这样数据更新只是「换文件」,不碰后端鉴权,也绕开每次请求动态计算的成本。
你会踩的三个坑
第一,adcode 前导零。乡镇代码以 0 开头很常见,用 Excel 打开或 parseInt 一搞就丢零,join 永远匹配不上,全表静默错位。第二,乡镇拆并滞后。民政部公告里「今日撤销 A 乡并入 B 镇」,但边界库里 A 乡还挂着老面,合并产生的缝隙不会自己消失,得跑拓扑修复。第三,坐标系混源。天地图出来的如果是 GCJ-02,别直接和 WGS84 的 OSM 混叠,先统一再入库,否则你对照的面积全是错的。
把这些捋顺,一套全国省市区县区划边界数据下载的自用源,就能从「碰运气」变成「可复现」。要精细化到全国村级geojson数据下载,也是同一套方法往下钻一层——多一份面积核对、多一道拆并追踪,仅此而已。
说到底,数据源管理的本质是给每一层数据记一笔「账」:它来自哪、什么时候更新的、用的什么坐标系、校验和是多少。账记清楚了,下次民政部发新公告、天地图更新某县边界,你半小时就能把整条链重新打一遍,而不是焦虑地重下一个看似一样、实则换过代的文件。这比我列的任何代码都值钱。