☰
百度地图API提取行政区边界并转ArcGIS标准Shp的完整方法
2026/10/20 16:39:57 网站建设 项目流程

做GIS项目的人应该都有过这种经历:需要一份杭州市的边界shp,结果网上下载的要么是几年前的旧区划,要么边界粗糙得只能看个大概轮廓,要么坐标系乱到叠不上任何底图。后来我换了个思路,用百度地图开放平台的行政区划查询接口把边界坐标一条条拉出来,再通过ArcGIS整理成标准shp文件,整套流程跑通之后发现这件事完全可以标准化、自动化。这篇就把完整做法拆开讲:怎么拿接口、怎么解析坐标、怎么在ArcGIS里成型,以及我踩过的坐标系和拓扑的坑。

1. 为什么放着现成的边界不用,偏要用API改造

做地理数据的人都清楚,行政区划shp是“高频消耗品”,但想在公开渠道找一份能直接用的杭州市边界,通常要碰运气。很多分享站点的数据下载下来,属性表里连行政代码都不全,边界轮廓也明显是矢量化描出来的,放到大比例尺下一看就露馅。所谓“现成”的文件,往往意味着你还要花大量时间检查精度、清理拓扑、补齐字段,成本一点都不低。

1.1 三种常见获取方式的实际体验

我常用的获取路径大概可以分成三类,各有各的优缺点:

获取方式优点缺点
公开数据网站直接下载方便快捷,市面流行格式通常都有数据时效性差,行政区划调整后容易旧;坐标系混乱;来源不明,难以商用
从API实时拉取边界坐标数据新,结构统一,支持批量获取,可自动化更新需要处理坐标字符串转要素,要写代码;坐标系需要额外处理
手动矢量化和配准完全可控,精度有保障工作量极大,杭州市边界这么复杂的形状,手工画基本不现实

拿杭州市来说,这些年部分县市撤市设区、街道重新划分,很多旧文件里的基层边界早就对不上现状了。API方式的核心价值不是“能省事”,而是“能拿新”,这也是我最后倒向接口路线的原因。

1.2 边界shp的“隐形要求”别忽略

很多人以为边界shp就是一条闭合的线框,导出就能用,其实项目里真正要落地的shp还包含不少隐性要求:

  • 必须是要素面,而不是单纯的线,这样后续做裁剪、叠加分析、统计面积才不会出岔子;
  • 属性表里要有关键字段,比如行政区划名称、行政代码,方便跟业务表做关联;
  • 坐标系要写清楚,否则换一台电脑打开就变成“未知来源”,叠加底图时位置完全乱掉;
  • 如果做专题图,还要保证边界没有缝隙、没有重叠,市级和区县级边界要能严丝合缝地套在一起。

百度地图API能解决数据“新鲜不新鲜、完整不完整”的问题,而ArcGIS能解决要素“规范不规范、能不能用”的问题。两件事拼在一起,才算把边界shp这件事情做完。

2. 先把“数据原料”搞清楚:行政区划接口能返回什么

有人可能会问,百度地图API不是做地图展示和路径规划的吗?怎么还能拉行政边界?实际上百度地图开放平台提供了一个专门的“行政区划查询服务”,只要传入一个行政区名称或编码,就能返回该行政区的中心点、行政代码、边界坐标串等基础信息。这个接口的本意是给开发者做区域圈选、行政区域高亮用的,但稍微加工一下,就能变成我们做GIS数据的好原料。

2.1 创建开发者应用,拿到AK

整个流程里最简单也最容易被卡住的就是这一步。你需要先在百度地图开放平台注册成开发者,然后创建“浏览器端”或“服务端”应用,系统会分配一个AK(API Key)。

接口请求必须在服务端发起,所以创建应用时建议选择“服务端”类型,否则容易出现跨域和Referer白名单的问题。我自己第一次就是随手建了个浏览器端应用,结果在Python脚本里直接请求,返回的是校验失败,换成语义未匹配的“ak无效”提示,排查了半天才发现是应用类型选错了。

创建完成之后,把AK复制出来,先存到环境变量或者配置文件里。千万不要硬编码在代码中并传到公开仓库,这个key就是你的凭证,泄漏出去等于别人可以拿你的配额刷请求。

2.2 最快的验证方式:直接在浏览器里请求一次

拿到AK后,不用急着写代码,先在浏览器地址栏里拼一个请求地址,确认接口是否通、返回结构长什么样。

https://api.map.baidu.com/api_region_search/v1/?ak=你的AK&region=杭州市&sub_admin=0&extensions=1

各个参数的含义很简单:

  • region:要查询的行政区名称,传“杭州市”或者“330100”这样的行政代码都可以;
  • sub_admin:是否返回下级行政区边界,0表示只返回杭州市本级,1表示连区县一起返回;
  • extensions:是否返回边界坐标,1表示返回,不传则只返回中心点和名称。

不同时期的接口版本返回字段略有差异,但通常都会包含一个类似boundary的字段,里面是一长串坐标点。这就是我们需要的原始边界数据,格式通常是经纬度成对出现,点与点之间用分号分隔,多个独立面之间可能还会用竖线分隔。

2.3 针对杭州市的返回字段拆解

以杭州市为例,正常返回的数据结构大致是这样:

{ "status": 0, "data": [ { "name": "杭州市", "adcode": 330100, "center": { "lng": 120.153576, "lat": 30.287459 }, "boundary": "119.956510,30.285282;119.956810,30.285482;..." } ] }

这个boundary字符串就是杭州市的边界轮廓,看起来像一堆乱码,实际上是一个多边形坐标序列。后面的所有工作,都是围绕如何把它转成可用的面要素展开的。

这里有个值得注意的点:接口返回的坐标值有小幅偏移,这是国内网络地图服务普遍采用的坐标规范,不是数据错误。后面专门用一章讲坐标系的问题,这步先记住“坐标是偏移过的”就够。

3. 坐标系这道绕不过去的坎,到底怎么处理

如果直接把API返回的坐标丢进ArcGIS,再用常见的互联网底图叠一下,你会发现杭州市边界整体位移了大概几百米,胳膊腿都对不上。这不是操作失误,而是坐标系体系不同导致的。

3.1 先认清BD-09、GCJ-02、WGS-84这三兄弟

做国内地图数据,绕不开三种坐标系:

  • WGS-84:GPS设备直接输出的原始经纬度,也是绝大多数国际开源底图采用的坐标系统;
  • GCJ-02:国内网络地图的应用坐标,高德、腾讯等都在用,也叫“火星坐标”;
  • BD-09:百度地图在GCJ-02基础上二次加密后的坐标系统。

百度地图开放平台接口返回的坐标,默认就是BD-09。如果把BD-09的坐标直接当成WGS-84的经纬度用,必然会产生肉眼可见的偏移。很多新手做国内边界数据时会困惑“为什么叠加底图永远差一截”,多半就是这个原因。

3.2 实际偏移有多大,肉眼可见

不同纬度的偏移量并不均匀,杭州这个位置,BD-09相对WGS-84的偏差通常是经度方向几十到几百米,纬度方向几十米到一百多米。对出图来说,这个误差直接导致边界挂在市区外面;对空间分析来说,更是无法接受。

所以在用ArcGIS导入前,必须先想清楚:你最终要把这份shp叠到什么数据上?

3.3 我建议的三种落地处理方式

根据项目用途不同,坐标处理方式也分三种,我按优先级排一下:

方式A:只用于百度相关场景如果这份shp只用来叠加百度地图的影像图或底图,那干脆不要转换。保持BD-09原坐标,在ArcGIS里把坐标系标记成自定义的经纬度坐标,叠百度底图时位置是完全吻合的。

方式B:叠国内其他地图平台如果最终需要叠高德或腾讯的底图,可以把BD-09转成GCJ-02。百度开放平台提供了坐标转换服务,可以批量处理坐标串,具体from和to的参数值以官方文档为准。

方式C:叠标准天地图或GPS数据如果要做严格的地理分析、跟GPS采集数据叠加,或者出规范图纸,就需要转成WGS-84。百度坐标转换服务同样支持这类转换,转换完成后在ArcGIS中把坐标系定义为GCS_WGS_1984即可。

3.4 ArcGIS里定义坐标参考的实操细节

坐标转换完成、数据导入ArcGIS后,还有一个不起眼但很关键的步骤:给图层声明正确的坐标参考。

如果直接从一个没有空间参考的文本导入,ArcGIS会把它当成未知坐标系。后续任何涉及投影、量算、叠加的操作都会报错或乱套。正确的做法是:

  • 在图层属性里查看“源”选项卡,确认坐标系是否已经识别;
  • 如果显示“未知”,手动指定为GCS_WGS_1984或目标坐标系;
  • 如果是已有边界的Geometry坐标已经是WGS-84,但图层属性里写错了其他坐标系,使用“定义投影”工具修正,而不是“投影”工具。

这个细节花不了两分钟,但能救回后面好几个小时的排查时间。

4. 从API返回字符串到ArcGIS图层的完整链路

坐标拿到之后,接下来的核心工作就是把字符串解析成标准GeoJSON,再交给ArcGIS完成最后一步转换。整个过程我习惯用Python处理,代码量不大,可复用性很强。

4.1 用Python把boundary拆成坐标点串

首先用requests发起请求,然后解析返回的boundary字段:

import requests import json ak = "你的AK" region = "杭州市" url = "https://api.map.baidu.com/api_region_search/v1/" params = { "ak": ak, "region": region, "sub_admin": 0, "extensions": 1 } resp = requests.get(url, params=params) data = resp.json() boundary = data["data"][0]["boundary"] print(boundary[:200])

boundary字符串的分隔符在不同接口版本里可能略有差异,稳妥的做法是同时兼容分号和竖线:

def parse_boundary(boundary_str): polygons = [] parts = boundary_str.split("|") for part in parts: coords = [] for point in part.split(";"): lng, lat = point.split(",") coords.append([float(lng), float(lat)]) if coords: polygons.append(coords) return polygons polygons = parse_boundary(boundary) print("多边形数量:", len(polygons))

杭州市的边界如果只看市本级,基本上是一个多边形,但真实的行政区边界可能存在飞地或岛屿,这时就会出现多面要素。用竖线分隔的思路可以把它们全部保留下来,避免丢失。

4.2 组装GeoJSON时的关键字段

GeoJSON是ArcGIS原生支持的交换格式之一,把解析好的坐标写入一个GeoJSON文件,后续导入就很顺:

geojson = { "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": { "name": data["data"][0]["name"], "adcode": data["data"][0]["adcode"] }, "geometry": { "type": "MultiPolygon", "coordinates": [ [[coord for coord in polygon]] for polygon in polygons ] } } ] } with open("hangzhou.geojson", "w", encoding="utf-8") as f: json.dump(geojson, f, ensure_ascii=False)

这里统一用MultiPolygon而不是Polygon,是为了兼容多面要素。即使当前只有一个多边形,MultiPolygon也能正常显示和计算,后续如果合并区县边界,可以少改很多代码。

4.3 在ArcGIS中导入GeoJSON并转成shp

我用的是ArcGIS Pro,直接把刚才生成的hangzhou.geojson拖进地图窗口就能预览。ArcMap用户可以在ArcToolbox里找到“JSON转要素”工具,选择对应的GeoJSON文件即可。

导入成功后,右键图层,选择“数据”中的“导出要素”,格式选shp,设置好输出路径和坐标系,一份独立的杭州市边界shp就生成了。

这里有个细节:如果之前做的是BD-09到WGS-84的坐标转换,那么生成shp时坐标系建议显式指定为GCS_WGS_1984。如果shp后续还要投影到某个投影坐标系,可以在导出时直接选择投影,让ArcGIS帮你完成从地理坐标到投影坐标的换算。

4.4 多部件要素:别把飞地弄丢了

杭州市边界在API返回中虽然大体连续,但杭州市行政区划内并不是一个绝对连续的封闭面,部分区域可能存在飞地或跨江的岛屿型地块。解析时如果只取第一个多边形,后续做面积统计就会少一块。

我的做法是保留MultiPolygon结构,导入ArcGIS后再用“多部件转单部件”工具检查一下要素数量。如果你发现面数明显不匹配,就要回头检查boundary字符串是否被截断,或者请求时extensions参数是否生效。

5. 成型之后,边界shp还得经历一轮“深度清洁”

拿到一份能显示的shp,只能算完成了一半。真正进入生产环境前,还要把边界做一轮清洁,否则叠加分析时很容易出现莫名其妙的误差。

5.1 市级边界和区县边界的合并

如果需求是杭州市市级边界,而API返回时带了13个区县的多边形,直接把多个要素融合成一个整体即可。ArcGIS里的“融合”工具(Dissolve)可以一键处理:字段选择不需要保留的字段,或者干脆不留字段,系统会把所有面合并成“杭州市”的完整轮廓。

融合之后要用“要素转面”工具重建拓扑关系,避免融合过程产生多余的悬挂线或微小缝隙。我第一次做的时候偷懒,融合完直接导出,结果边界放大到一比一万时能看到裂缝,后续做裁剪分析时漏了很多小斑块。

5.2 拓扑检查:缝隙和重叠一个不留

边界数据最怕两个问题:面与面之间有缝隙,或者相邻面相互重叠。缝隙会导致统计时“查不到”某些区域,重叠会导致重复统计。

在ArcGIS里建一个要素数据集,把边界图层放进去,然后新建拓扑,规则选“不能有缝隙”和“不能重叠”,系统会自动标记所有问题位置。修复缝隙通常用“延伸”或“更新”工具,重叠则用“擦除”把多余部分去掉。

这个环节看起来繁琐,但对后续要做空间连接、面积统计、叠加分析的场景来说,省掉这步就是给自己埋雷。

5.3 属性表设计:从够用到底层规范

一份能上生产环境的边界shp,属性表最好包含以下字段:

字段名类型说明
nameText行政区名称,如“杭州市”
adcodeLong行政区划代码,如330100
levelText级别,如“province/city/district”
sourceText数据来源标记,标注百度地图开放平台
update_timeDate数据获取时间,方便日后核查时效

尤其是update_time字段,别嫌多此一举。行政区划会调整,你不能保证半年后的自己还记得这份数据是什么时候拉的。有没有这个字段,直接决定后续更新时能不能快速判断“旧数据要不要淘汰”。

5.4 不同比例尺下的显示精修

边界数据在不同比例尺下显示的观感差异很大。市级边界在1:10万比例尺下可能只需要平滑的轮廓,但放大到1:1万就会看到很多细节毛刺,甚至出现自相交。

ArcGIS的“简化面”工具可以处理这些毛刺,简化容差建议根据最终出图比例尺来定。容差设大了,小湾小角会被磨平;容差设小了,毛刺还在。我一般先做一个200米左右的简化测试,对比看效果再决定是否调整。

6. 这趟流程里最容易翻车的几个细节

最后把实际踩过的坑集中聊一聊。这些事情单独看都是小问题,但凑在一起就是整整半天的排查工作量。

6.1 返回的“杭州市”到底包不包括区县

行政区划查询接口有个容易误会的点:查询“杭州市”返回的boundary,是杭州市级行政区的整体轮廓,还是下辖各区县的组合?

不同参数和不同接口版本表现不一致。如果sub_admin设为1,返回的是下级行政区列表;如果设为0,一般返回的是市本级整体边界。问题是有些接口版本即使sub_admin=0,也可能把代管县市的边界一起揉进轮廓。最稳妥的办法是:拿到boundary后用ArcGIS打开,数一下多部件数量,再跟实际区划数量对照。

6.2 行政区划调整会让历史数据失效

杭州市近年经历过撤市设区等区划调整,如果你从网上找到一个三年前的shp,边界大概率已经过时。这也是为什么我强烈建议用API现拉数据,而不是长期存一个固定文件。行政区划变更后,只要重新跑一遍脚本,新数据就到手了。

6.3 别把接口精度当成万能数据源

这个接口适合做宏观分析、示意图、出图底图,但不适合做土地确权、不动产登记这类需要高精度权籍边界的工作。API返回的边界精度通常是行政区划示意级别的,跟测绘部门发布的标准行政界线存在差异。涉及法律和权属问题时,必须以官方权威数据为准。

6.4 合规使用与地图审核的底线

使用百度地图开放平台的数据,需要遵守开放平台的开发者服务条款。拉取数据供内部项目分析一般没有问题,但若要把边界文件对外发布、嵌入商业产品,或者制作公开地图,必须确认授权范围,并按规定在地图上标注来源信息。地图发布在国内有严格的管理要求,做任何公开传播前都要先过合规这一关。

最后分享一个小习惯:我把AK和区域名称做成一个简单的CSV清单,每次项目开工前跑一遍脚本,杭州市十几个区县的边界数据十几分钟就能全部更新完。遇到需要出纸质图的场景,再在ArcGIS里手动微调一圈。做数据这种事,最怕临时抱佛脚,平时把工具链备好,用的时候真的能省下半天时间。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询