ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

全国分省市OSM数据裁剪全流程解析:从PBF到GeoPackage的实践指南

全国分省市OSM数据裁剪全流程解析:从PBF到GeoPackage的实践指南

2025年做地图相关的事情,基本绕不开 OpenStreetMap(OSM)。最近我在整理一套“全国分省市”的 OSM 底图数据,原本以为无非就是下载一个全国包,再按省界裁一裁,真正跑起来才发现,把全国所有省级行政单位从全量数据里拆出来,再把重点城市往下细分,每一步都藏着不少道道。这篇文章就把完整的数据加工逻辑、实操过程和踩坑记录梳理一遍,给同样需要处理 OSM 行政区划数据的朋友做一个参考。

先说清楚这套数据是什么:它基于 2025 年上半年的 OSM 公开全量矢量数据,经过省级、地市级两级裁剪,最终生成一套覆盖全国范围、以各省市为单位独立管理的矢量数据包。适合做地图底图、路径规划前的路网整理、POI 匹配、片区空间分析等场景,尤其适合那些不希望每次都拿全量全国数据去跑项目的开发者和分析人员。下面按从需求拆解到最终交付的顺序,把整个活儿讲透。

1. 全国分省市 OSM 数据的需求与设计思路

1.1 OSM 数据到底能提供什么,为什么非要按省市切分

OSM 是一套全球协作维护的开放空间数据,要素类型非常丰富,除了我们最熟悉的路网以外,还有建筑轮廓、水系、绿地、铁路、公交站点、各类 POI。它最大的优点是免费、更新频率高、属性结构统一,很多人拿它做底图或者训练数据。

可是 OSM 的全球数据是整体打包发布的,一个全国文件常常有几个 GB,直接放进业务系统里查询会非常吃力。再加上国内行政区划边界、道路管理归属、各类应用场景都要按省市划分数据权限,做全国级别的分析时如果不把数据切分好,下游的每一次数据抽取都得加载一遍全量数据,效率低且难以维护。所以“全国分省市”不只是数据组织习惯,更是工程项目里的刚需。

为什么不用在线 API 直接按范围拉取?因为一次 API 拉取通常只能覆盖一个城市级别的范围,而且有配额限制,数据完整性和时效性也难保证。最稳妥的方案是拿一份全国全量 PBF,在本地用边界文件做一次性裁剪,得到各省市的独立数据文件,后续再按需合并或抽取要素。这样生成的数据语义清晰、版本可控、可重复加工。

1.2 不同数据源和切分策略怎么选

网上能拿到 OSM 全国数据的地方不少,常规渠道有全球镜像、第三方导出工具和一些提供定制切片的服务商。它们的数据鲜度、切分粒度差别挺大:

渠道类型数据粒度优点注意点
全球公开镜像完整 PBF,按洲或国打包数据全,适合本地二次加工文件体积大,首次下载耗时
第三方行政边界导出部分已有省市分类省去自己裁剪边界可能过时,属性标准化程度不一
在线 API 拉取按包围盒或关系提取适合小范围快速获取有范围限制,不适合全量批量
自主研发裁剪任意边界组合灵活可控,能统一坐标系和属性需要自己准备边界文件和工具链

在实际项目中,我一般推荐走“全量 PBF + 本地裁剪”的路线,因为这套流程在数据更新时只需要重跑一次裁剪脚本,就能保持所有省市文件的同步更新。如果直接依赖第三方现成的省市数据包,虽然省事,可一旦遇到边界调整或者要素修正,很难跟上节奏。自己做裁剪,前期多一些工作量,但胜在可控。

为了避免数据处理过程中边界口径不一致,我的设计思路是:先确定一套统一边界数据(建议用某数据源提供的标准行政边界 GeoJSON),然后基于这套边界去裁剪全国 PBF,保证所有省市文件的行政归属一致。这比按包围盒去切要严谨得多,因为包围盒是矩形,会把相邻省市的要素一并框进来,给后期清洗带来额外负担。

2. 核心技术点拆解:数据格式、坐标体系与裁剪逻辑

2.1 PBF、GeoJSON、Shapefile 到底怎么选

OSM 的原始数据是 XML 或者 PBF 格式。XML 易读但体积巨大,2025 年的全国全量 XML 动辄几十 GB,实际工程里基本不碰;PBF 是二进制压缩格式,体积小、解析快,是官方主推的数据交换格式。所以第一步拿到手的应该是全国 latest 版本的 PBF 文件。

后续按省市裁剪后,输出格式就要根据需求来定了:

  • 如果只是做中间结果,继续保留 PBF 就好,后面还能用各类工具再加工;
  • 如果要入库到 PostgreSQL/PostGIS 或者做空间分析,GeoJSON 是最省心的,因为 GDAL、Fiona、GeoPandas 都原生支持;
  • 如果对接的是老 GIS 软件,或者需要带字段样式进入传统管线,Shapefile 仍然有它的江湖地位,只是字段名长度限制、文件多文件支撑这些老问题要心里有数。

我个人的经验是:边界文件用 GeoJSON,裁剪中间产物用 PBF,最终面向业务系统的底图用 GeoPackage 或 Shapefile。GeoPackage 是单文件、支持空间索引、字段类型更丰富,现在很多地图应用已经默认支持,比 Shapefile 更适合作为交付格式。

2.2 坐标系与地理配准:为什么 OSM 数据要特别留意偏移

OSM 的数据本身是基于 WGS-84 经纬度坐标系的,也就是 GPS 设备常用的全球坐标。这个坐标系本身没毛病,问题在于国内地图服务普遍使用加密坐标系,两者之间存在着非线性偏移。直接拿 OSM 的 WGS-84 数据叠到某商业地图底图上,会看到道路和建筑错位几十到几百米不等。

所以如果只是做内部空间分析、路网建模、POI 匹配,保留 WGS-84 没有问题;但如果要跟国内主流地图混合展示,就必须先做坐标转换。这个转换不是简单加减偏移量,而是需要调用相应的纠偏算法或服务,“固定偏移量”的做法只能在小范围勉强用,放到全国尺度上误差会明显增大,容易出现在同一城市不同区域内偏移方向不一致的情况。

坐标系的处理应该在裁剪之前统一好。我建议先保持原始坐标系做完所有裁剪和属性操作,最后到成图阶段再按业务需要投影或切换。因为裁剪阶段一旦做了坐标系转换,边界匹配容易出问题,后续想要回到原始坐标反而麻烦。

2.3 裁剪算法原理简析:不是“画个框切一刀”那么简单

按省市裁剪看起来像是在全国地图上拿一把剪刀剪出各省的形状,实际落地时有个核心难点:边界线附近的要素怎么归属。比如一条横跨两个省的公路,在 OSM 里可能是一条完整的长 LineString,并不会因为省界就被拆成两段。如果只用简单的多边形相交判断,这条公路要么整条留在 A 省,要么整条划给 B 省,跟真实情况不符。

更合理的处理方式是先做边界要素的切割,再根据要素几何与各省多边形的位置关系做归属分配。像路网、水系这类跨越边界的线状要素,通常要把几何按边界线切分后,分别归档到对应省份。建筑、POI 这类点状或面状要素则相对简单,根据中心点或几何重心落在哪个省内来判断归属即可。

Osmium 这类工具内部实现其实做了比较复杂的空间索引和几何切割,它并不只是判断“是否在框内”,而是会考虑线和边界多边形的关系,对挂在边界上的要素做切割处理,从而保证每个省的数据是相对完整的。理解这一点很重要,否则当你发现省会城市周边道路总在边界处断开,还以为工具出了问题,其实是裁剪逻辑本来就是这样设计的。

3. 实操全过程:从下载到出成果

3.1 环境准备:工具清单与安装要点

工欲善其事,必先利其器。我这次用的组合是:

  • osmium-tool:负责 PBF 提取和边界裁剪
  • GDAL/OGR:负责格式转换和矢量操作
  • Python 3 环境,配合 geopy/pyshp/geopandas 做批量处理
  • QGIS:用于人工抽检边界和要素分布

osmium-tool 是命令行工具,安装很直接,macOS 上直接用 brew 装即可,Windows 下可以下载预编译包放 PATH 里。这个工具对内存和 CPU 的利用率很高,裁剪全国数据时如果机器的内存不足 8GB,建议先做层过滤再裁剪,不然内存会被撑爆。

GDAL 是重头戏,在很多发行版里可以直接通过包管理安装,装完以后要顺手验证一下 ogrinfo 命令是否可用。另外一个容易忽略的点是:处理中文属性值时,一定确保系统 locale 支持 UTF-8,否则后续转 Shapefile 时字段名和属性值都可能出现乱码。

3.2 获取全国 PBF 数据:版本选择与下载校验

下载这一步看起来简单,但有几个细节值得盯一下。一是要选对文件版本。公开的国内全量数据通常有“latest”和带日期的快照版本,为了确保成果可复现,我建议下载带日期的版本,文件名里注明具体日期,这样以后回溯数据修改时间点时有据可查。二是下载后要做完整性校验,通常数据源会同时提供一个校验文件,用系统自带的校验工具跑一遍摘要比对,确保文件没有在传输过程中损坏。

实际下载命令类似于:

wget https://某数据源路径/china-250101.osm.pbf wget https://某数据源路径/china-250101.osm.pbf.md5

接着做哈希校验:

md5sum -c china-250101.osm.pbf.md5

看到输出里出现 OK 字样,才代表文件完整。这一环节很容易被忽略,可一旦文件在传输中被截断,后面的裁剪会失败或者得到错误数据,排查起来非常浪费时间。

拿到 PBF 后,我先用 osmium 把全国 PBF 里面比较占空间但业务中不太需要的类型做一次粗筛。比如如果做的是道路和建筑分析,可以先按类型提取所需要素,保留到中间 PBF,这样后续裁剪的压力会小很多。

osmium tags-filter china-250101.osm.pbf w/highway w/waterway w/building r/route a/amenity -o china-filter.osm.pbf

这里要解释一下:w/代表 way,r/代表 relation,a/代表 area,后面跟的是标签条件。这样筛出来的中间文件会比原始文件小不少,处理速度自然就上来了。

3.3 准备省市边界文件:统一口径的关键

全国省市边界数据的收集,是需要特别细心的一步。很多人会从各类在线地图抓取行政边界,但这些边界很可能自带坐标偏移、边界顶点简化过度、不同层级边界互相矛盾等问题。我建议使用规范发布的行政边界 GeoJSON,并且统一采用 WGS-84 坐标,避免和 OSM 源数据坐标不一致。

边界文件到手后,第一件事是检查属性表里是否有省级代码、省级名称、地级市名称、地级市代码这些字段。因为这个字段将决定后面批量命名和分类是否正确,省一级和市一级的数据能不能分别整理出来都依赖它。若字段不完整,可以用代码表和名称做一个匹配映射表,再用脚本补全属性。

为了让后续按省、按市批量裁,我习惯把边界文件按照层级存成两个目录:一个放省级边界,一个放地市级边界,文件命名统一采用“行政区划代码+名称.geojson”的形式。比如“某省.geojson”“某市.geojson”。代码和名称直接写在文件名里,后面的裁剪脚本就能自动生成输出路径,不需要每次手动改配置。

3.4 核心裁剪步骤:osmium extract 批量实施

边界和源文件都备齐后,裁剪过程就简单了。osmium 的 extract 子命令按多边形边界读取数据,基础命令长这样:

osmium extract -p 某省.geojson china-filter.osm.pbf -o 某省.osm.pbf

加--overwrite可以在重复执行时覆盖已有文件。这里有一个很重要的参数叫--strategy,它控制的是完整区域提取还是简单区域提取。默认的 complete_ways 策略会保留跨越边界的完整线要素,而 simple 策略则按相交关系切分。对于路网这种连续要素,我更推荐用 complete_ways,以保证每个省内的公路是连续完整的,后续做路径规划时不会出现到了省界就断掉的问题。

批量跑的时候,我用一个简单的 bash 脚本,遍历省级边界目录下的所有 GeoJSON 文件,逐个调用 extract。示例脚本如下:

for f in boundaries/province/*.geojson; do name=$(basename "$f" .geojson) osmium extract --overwrite -p "$f" china-filter.osm.pbf -o "output/province/${name}.osm.pbf" done

省级裁剪完成以后,再针对地市级边界跑一遍同样的流程,只是输出目录换成地市级目录。这里特别提醒:地市级裁剪应该基于裁剪后的省级 PBF,还是基于全国 PBF?

按常理,地市属于省,直接从全国文件里裁也可以,但为了保持数据的一致性和减少 I/O 开销,我建议先裁省,再从各省的 PBF 里裁市。这样每个市的数据严格是省级成果的子集,不会出现省数据和市数据范围打架的现象。

3.5 数据校验:裁剪结果不可省的一道工序

不能剪完就认为大功告成。裁剪之后我一般做三个层面的校验:

  1. 要素数量级对比:对比全国 PBF、省级 PBF、地市级 PBF 的要素数量,可以直观看出数据是否有异常丢失。比如某省数据量比相邻省份少一个数量级,那基本可以断定边界或者裁剪参数出了问题。
  2. 地理范围检查:用 ogrinfo 或者 QGIS 打开边界文件,检查数据的包围盒是否落在该省市范围内,以及是否存在加载出来空白、坐标系异常的情况。
  3. 属性标签检查:抽取一部分要素,确认 OSM 标签字段还在,比如公路的highway值、建筑的building值没有丢失。

关于第二点,我提供一个小命令,可以快速查看 PBF 基本信息:

osmium fileinfo --extended 某省.osm.pbf

它会输出文件的总对象数、节点数、路径数、关系数、坐标范围等元数据。坐标范围这个指标最有用,一眼就能看出数据是否真的落到了目标省市附近。如果范围对不上,那说明边界文件和裁剪流程里有逻辑错误,要立刻排查。

3.6 导出为业务可用的格式:GeoPackage 与 Shapefile

裁剪后的一堆 PBF 还不是最终交付物。如果要进入业务系统,通常还要转一次格式。我用 ogr2ogr 把 PBF 转成 GeoPackage,这一步能把点、线、面分层导入,数据库和 GIS 软件都能直接读取。

ogr2ogr -f GPKG 某省.gpkg 某省.osm.pbf

如果要把 OSM 的线、面混合数据拆分到不同图层,可以用-where或者-sql参数做 SQL 级的过滤,把它拆分成roads、buildings、waterways这些专题层。这样做对后续使用特别友好,因为 OSM 原生数据是单图层混杂的,不拆分的话业务端每次都要过滤标签,查询效率很低。

如果对接的老系统只认 Shapefile,那导入后要注意字段名长度限制问题。OSM 的标签字段经过转换后常常变成很长的键名,Shapefile 单个字段名不能超过 10 个字符,直接转换会导致字段名被截断,最好在导出前用 SQL 语句统一重命名。

4. 常见问题与排查技巧实录

4.1 边界数据缺失或错位

做裁剪时最常见的问题是边界文件本身有问题。有时候从网上下载的边界 GeoJSON 缺了一个小岛,有时候边界顶点密到极点,在裁剪时会把相邻地区的零星要素带入目标区域,导致边界处出现一些“飞地”要素。

排查思路很简单:先用 QGIS 打开边界文件,重新投影到 Web 墨卡托底图上,人工看一下边界是否闭合、是否覆盖完整。再用 osmium extract 之前,用 ogrinfo 检查边界文件属性,确认坐标范围不超过该省市的实际经纬度范围。

处理飞行地要素的办法有两个:一是裁剪后按要素中心点再做一次归属校验,二是直接给边界做一些小的缓冲区收缩,把边界线两侧各缩几米,把误差范围压到最小。对于要求不那么严格的场景,缓冲区收缩效果很好;但如果是做精细路网,就用中心点归属校验更稳。

4.2 裁剪后要素数量差异过大

有时候两个相邻面积差不多的省,裁剪出来的要素数量能差 3 倍以上。这个现象不一定是错误,更多是数据覆盖度不均导致的。因为 OSM 在国内的要素详情程度本身就有地区差异,经济发达、活跃用户多的地区数据明显更细,偏远地区可能只有主要公路和稀疏建筑,要素数量自然差别巨大。

不过如果某个省份裁剪前后完全没产出任何 PBF 文件,那大概率是边界文件名和行政区划代码匹配出了问题。我在第一次跑批时就遇到过一个城市因为边界文件里没有对应代码,脚本直接跳过,导致输出目录里少了一个省。解决方法是写一个简单的清单比校脚本,把输出目录的文件清单与边界目录逐一对比,缺哪个就补哪个。

另外要注意一个容易踩的坑:全国 PBF 里部分边界附近的数据可能因为原始绘制的关系,行政归属并不精确,裁剪时要素跨越边界的情况非常频繁。省界附近可以定期抽检,看看是否存在明显的距离误差,再用数据清洗手段处理,避免把这些错误带进最终业务分析。

4.3 中文乱码与属性丢失

OSM 的属性值是 UTF-8 编码,在转 Shapefile 时如果系统默认编码不是 UTF-8,就会出现乱码。解决方法是导出时显式指定编码:

ogr2ogr -lco ENCODING=UTF-8 -f "ESRI Shapefile" 某省.shp 某省.gpkg

属性丢失一般出现在标签过滤阶段。若用 tags-filter 筛数据时只保留了部分标签,那么后面导出自然少字段。解决的方法是明确列出需要的标签,或者在裁剪完成后用 osmium tags-filter 再补一步全标签提取,把常用标签合并进结果。我个人的习惯是先用全量标签裁剪,导出到 GeoPackage 的阶段再做图层拆分,这样能保留最完整的属性信息,后续使用灵活。

4.4 内存与性能优化

裁剪全国 PBF 时最影响体验的就是内存占用。osmium extract 默认会读入大量节点信息,如果文件到了多 GB 级别,内存不够时会明显变慢甚至报错。我的处理经验是尽可能先做标签过滤,把不相关的要素剔除;再按大区拆分,比如华东、华北,先拆成若干中间块,再从中间块里提取省市。

对于多核服务器,可以并行跑多个 extract,但要注意磁盘 I/O 瓶颈。三个并发进程以内通常能线性加速,开太多反而因为磁盘读写争抢而整体变慢。另外,把源 PBF 放到 SSD 上能明显提升裁剪速度,这个差异在处理十 GB 级文件时非常明显。

4.5 裁剪后数据更新时间不同步

OSM 每天都有变化,可能今天导出的全国数据和本周第一次导出的、上月的都不尽相同,所以数据的“时效性说明”非常重要。建议在最终交付目录里单独放一个 README 文件,记录源数据快照日期、边界数据来源版本、裁剪工具版本和命令参数。这样即使过几个月后再重新生成,也能知道和旧版本的差异点。每个省市包内也可以记录一个source.txt,写清楚数据来源和时间,这是很多项目审阅时必须的追溯材料。

5. 这份数据能做什么,以及后续扩展方向

5.1 地图可视化与导航底图

处理好的省市 OSM 数据最直接的应用是做可视化底图。把裁好的 GeoPackage 导入地图引擎,配合道路等级样式渲染,短时间内就能生成一套风格统一、免费可用的地图底图。对于跨省物流、旅游出行这类需要多区域底图叠加的业务,分开管理的省市数据反而比全国整体数据更容易做按需加载,用户滑动地图到哪个省就加载哪个省的数据,性能优化空间很大。

如果要做路径规划,建议在裁剪时保留完整路网关系,并额外用 OSM 的高等级道路标签做一层过滤,生成一张更适合路径计算的路网底图。再结合导航引擎的拓扑规则,做一个简单的路网连通性检查,尤其是省界附近是否存在断裂,这个检查能省去后期大量定位 bug 的时间。

5.2 城市规划与基础设施分析

OSM 里的建筑、水系、绿地数据在城市规划分析中很有价值。比如利用建筑轮廓数据计算片区的建筑密度,利用水系数据做洪水影响范围粗分析,利用绿地公园数据做居民步行可达性研究。这些分析通常不需要购买商业数据,OSM 已经能提供一个不错的底数。

使用时要记住:不要把 OSM 数据当作官方权威数据。它的某些区域更新非常及时,某些区域又长时间没人维护,数据密度不代表真实情况。在输出分析结论前,建议先做一个数据覆盖度可视化,看目标区域的数据完整性是否满足分析要求。如果区域内明显有大量村庄没有建筑轮廓,那分析时就要对缺失情况做说明,避免结论失真。

5.3 与自有数据融合的注意事项

把 OSM 数据和业务采集的 POI、房屋产权数据做融合是另一个常见场景。融合前最重要的事是统一坐标系和 ID 体系。OSM 的 ID 是全局递增的,在裁剪、转换后并不会保留原始关系 ID 的稳定值,所以不要拿 OSM 的 ID 作为业务数据的关联键,应该用经纬度加标签属性做空间联合方式匹配。

融合时如果发现业务数据点在 OSM 边界里找不到对应的面要素,不要急着丢弃,很可能是两个数据源采用了不同的边界口径。解决方法是先把业务点落图,人工抽几个样本判断是否存在系统性偏移。如果偏移方向一致,可以统一做一次坐标修正;如果方向不一致,则要回到数据源排查采集问题。

5.4 从省内再进一步:按区县细分

省级、市级数据都做好了,后续如果业务需要下沉到区县,完全可以复用这套流程,只要把边界文件换成区县级 GeoJSON,重跑一遍裁剪脚本就行。这也是我不建议直接使用网上现成省市包的原因——行政区划调整一旦发生,区县边界就变了,而利用脚本和边界目录重跑一套数据,成本非常低。

在脚本设计上,我的做法是写一个三层循环,分别遍历“省→市→区县”,输入统一边界目录,输出三级目录结构。这样不管是完整跑全国,还是单独重算某个省,都能一键完成。为了让模块便于维护,我把边界目录、源数据路径、输出目录都抽成配置变量,换一套行政区划数据也能直接复用,不需要改代码逻辑。

最后的经验小结

把 2025 年全国分省市 OSM 数据完整做下来,我最大的感受是:技术上真正难的不是某一个环节的单独实现,而是从全国 PBF 到分省市数据这个过程中,如何保证边界一致、属性完整、更新可追踪。很多时候花在排查上的时间,比裁剪本身还多。建议第一次接触这套流程的朋友,先把边界文件、源数据、输出目录的命名规范定下来,后续所有脚本都围绕这个规范写。哪怕初期多花半小时做规划,后面重跑数据时你会回来感谢自己的。

另外一个建议是:数据交付时一定要带上生成说明文件。文件里写清楚源数据日期、裁剪策略、边界来源和坐标信息。这不仅是项目管理的需要,也是同一份数据在不同团队成员手里能保持口径一致的基础。数据本身做得再好,如果离开了这些元信息,过几个月再被别人拿来用,很可能就被当成普通数据直接使用,而忽略掉它的时效性和适用边界。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进