城市POI数据的获取,是很多做地理分析、选址评估、商业调研的朋友绕不开的一道坎。我最早接触这个需求,是帮一个做连锁零售的朋友评估新店选址,当时需要把目标城市里所有同类门店、商圈、交通设施的位置全捞出来做热力分析。一开始想得很简单,不就是查个地图嘛,结果真动手才发现,数据来源、坐标体系、字段结构、更新频率、合规边界,每一项都能卡住人。后来陆陆续续做了十几个城市的POI采集项目,踩过的坑攒了一箩筐,也总结出一套相对稳定的流程。
这篇内容想聊的就是“获取各城市POI数据”这件事本身——它到底包含哪些环节,不同来源的数据有什么差异,坐标怎么统一,字段怎么清洗,批量跑多城市时怎么组织流程,以及哪些地方最容易翻车。适合刚接触空间数据的新手,也适合已经会用但总觉得数据“不太对劲”的同行。我会尽量把原理讲透,把操作步骤写到能直接照着做的程度,同时把那些文档里不会写的经验教训摊开来说。
1. 先搞清楚POI数据到底是个什么东西
1.1 POI的本质与字段构成
POI是Point of Interest的缩写,中文一般叫兴趣点。听起来玄乎,其实就是一个带坐标和属性的地点记录。你打开手机地图搜“咖啡”,跳出来的每一个结果,背后就是一条POI数据。一条完整的POI通常包含几个核心字段:名称、类别、经纬度坐标、地址、所在行政区划,有些来源还会附带电话、营业时间、评分、标签等扩展信息。
理解字段构成很重要,因为不同来源的POI在字段完整度上差异极大。有的来源只给你名称和坐标,类别是粗粒度的;有的来源类别体系非常细,但坐标精度一般。做多城市采集时,如果一开始没想清楚自己要哪些字段,后面清洗阶段会非常痛苦。我一般会在项目启动前先列一张字段需求表,把“必须有”“最好有”“可要可不要”三档分清楚,再去找匹配的数据源。
类别体系是POI数据里最容易被低估的部分。同样是“餐饮”,有的体系分到“中餐-川菜-火锅”这种四级粒度,有的只到“餐饮服务”一级。类别粒度直接决定了你后续能不能做细分分析。比如做商圈业态分析,如果类别太粗,你根本区分不出快餐和正餐的比例,分析结论就会失真。所以选数据源时,类别体系的深度要和你的分析目标对齐,不能只看数据量。
坐标这块也要提前有概念。国内主流地图服务使用的坐标系并不统一,常见的有WGS84(GPS原始坐标)、GCJ02(俗称火星坐标,多数国内地图产品使用)、BD09(某地图产品专用)。如果你从不同来源拿数据再混在一起用,不统一坐标系,点位会整体偏移几百米,做空间叠加分析时完全对不上。这个坑我在早期项目里踩过,两个来源的数据叠在一起,门店位置全飘到马路对面去了,排查了半天才发现是坐标系没转换。
1.2 为什么“各城市”这个限定词很关键
单城市采集和多城市批量采集,难度不是一个量级的。单城市你可以手动调边界、人工核对异常点,多城市就必须把流程自动化,否则几十个城市跑下来人会疯掉。多城市带来的第一个问题是行政区划边界的管理。每个城市的行政边界、下辖区县结构都不一样,你需要一套可靠的区划编码体系来组织采集任务和后续的数据归档。
第二个问题是采集配额和频率控制。多数数据服务对调用量有约束,多城市批量跑的时候,如果不做任务排队和限流,很容易中途被拦。我一般会把城市按优先级排序,分批跑,每批之间留出间隔,同时记录每个城市的采集状态,断了能续。第三个问题是数据一致性。不同城市的数据在字段命名、类别编码、坐标精度上可能有细微差异,采集完必须做一轮标准化,否则合并成全国表的时候会出现各种脏数据。
还有一个现实问题:城市规模差异巨大。一线城市的POI动辄几十万上百万条,小城市可能只有几万条。如果按统一的分页策略去拉,大城市容易超时或触发限制,小城市又浪费请求。我的做法是先按城市等级或预估数据量做分组,大城市场景用更细的地理网格切分采集,小城市直接整城拉取,这样整体效率最高。
2. 数据来源怎么选:几条主流路径的取舍
2.1 公开地图服务的检索能力
最直接的路径是利用公开地图服务提供的地点检索功能。你在网页或开放接口里输入关键词和城市名,它返回结构化的地点列表。这条路线的优点是上手快、覆盖广、类别体系成熟,缺点是通常有调用频率和返回数量的约束,深度采集需要配合地理范围切分。
用这条路线的核心技巧是“网格切分”。不要指望一个城市用一个关键词一次拉完,而是把城市按矩形网格切成小块,每个网格内再按类别关键词分别检索,最后合并去重。网格大小的选择有讲究:太大容易触达返回上限导致漏数据,太小则请求数暴涨。我的经验是先拿城市中心区域做小样本测试,看单网格返回量,再反推合适的网格尺寸。一般让单网格单类别的返回量控制在返回上限的六七成比较稳妥,留出余量。
关键词的设计也直接影响召回率。同一个业态可能有多种叫法,比如“便利店”和“超市”在不同城市的实际命名习惯不同。我会为每个大类准备一组同义词,检索时轮换使用,合并后去重。这一步看起来笨,但实测召回率提升明显,尤其是中小城市,很多店名不规范,单一关键词会漏掉不少。
2.2 开放数据平台与行业数据集
不少城市有开放数据平台,会定期发布部分类别的POI数据,比如公共服务设施、文化场馆、医疗机构等。这类数据的优点是权威、字段规范、可追溯,缺点是类别覆盖不全、更新频率不固定、格式五花八门。做特定主题分析时,这类数据是很好的补充甚至首选,但做全类别商业分析就不够用了。
行业数据集是另一条路。市面上有一些整理好的城市POI数据集,按城市打包出售或开放下载。选这类数据时要重点看三件事:采集时间、坐标体系、类别标准。采集时间决定了数据新鲜度,商业类POI变化很快,一年前的数据和现在的可能差出两三成。坐标体系前面说过,不统一就得转换。类别标准要看是否和你后续的分析框架兼容,不兼容就得做映射表。
我一般会把公开服务和开放数据结合使用:用公开服务做全类别的基础采集,用开放数据对重点类别做校验和补充。两条来源交叉比对,还能发现一些明显错误,比如某条记录坐标落在河里或者行政区划对不上,这种异常点单独拎出来人工核一下,能显著提升数据质量。
2.3 来源选择对比表
| 来源类型 | 覆盖广度 | 字段完整度 | 更新频率 | 主要限制 | 适用场景 |
|---|---|---|---|---|---|
| 公开地图检索 | 广 | 中高 | 较新 | 有调用约束,需切分 | 全类别基础采集 |
| 城市开放数据 | 窄 | 高 | 不定 | 类别不全 | 公共服务类专题 |
| 行业数据集 | 中 | 中 | 取决于采集时间 | 需核验新鲜度 | 快速起步、补充 |
| 实地采集 | 窄 | 极高 | 最新 | 成本高、周期长 | 重点区域精查 |
这张表不是让你只选一条路,而是帮你判断在什么阶段用什么来源。实际项目里往往是组合拳:先用行业数据集快速搭底表,再用公开服务补全和更新,重点区域用实地采集校准。组合使用时要特别注意去重逻辑,同名同坐标的记录合并,同名但坐标距离较远的要保留并标记,因为可能是同名不同店。
3. 多城市批量采集的流程设计
3.1 任务编排与城市清单管理
批量采集的第一步不是写代码,而是把城市清单和任务结构理清楚。我会建一张城市任务表,字段包括城市名称、行政区划编码、预估数据量等级、采集状态、采集时间、数据条数、备注。这张表是整个流程的指挥中心,跑批的时候程序读它、更新它,出问题也靠它定位。
城市清单的来源要可靠,一般用标准行政区划编码表,确保城市名称和编码一一对应。这里有个细节:有些城市存在同名区县或者名称变更的情况,直接用名称做键容易出错,用编码做键最稳。采集时把编码带上,后续归档和合并都方便。
任务编排上我习惯按“城市-类别-网格”三级组织。外层循环城市,中层循环类别,内层循环网格。每一级都记录完成状态,这样中途中断后可以从断点续跑,不用整城重来。状态记录建议落到文件或轻量数据库里,别只放内存,跑长任务时内存状态一丢就前功尽弃。
3.2 限流、重试与断点续跑
限流是批量采集的生命线。我的做法是给每个请求之间加固定间隔,同时监控返回状态,一旦出现频率相关的错误码就自动拉长间隔并暂停一段时间。间隔的具体数值没有标准答案,取决于所用服务的约束,一般从保守值开始试,稳定后再逐步收紧。
重试策略要区分错误类型。网络超时这类临时错误,重试两三次通常能过;返回空结果不一定是错误,可能是该网格确实没数据,不能盲目重试;权限或配额类错误重试也没用,应该暂停并告警。我一般给每个请求打上重试计数,超过阈值就跳过并记录到异常清单,事后统一处理,避免单个请求卡死整个批次。
断点续跑的关键是状态持久化。每完成一个网格就写一次状态,粒度不要太粗。我见过有人按城市记录状态,结果一个城市跑到九成断了,续跑时整城重来,浪费大量请求。按网格记录虽然写状态频繁一点,但续跑成本低得多,整体算下来更划算。
3.3 采集结果的落盘与初步校验
数据落盘我倾向用结构化格式,每条记录一行,方便后续处理。落盘时就把城市编码、类别、采集时间这些元信息带上,别等到清洗阶段再补,补的时候容易对不上。文件按城市和批次分目录存放,命名规则统一,后面合并时按规则扫描就行。
初步校验在落盘后立刻做,主要看三件事:条数是否在合理范围、坐标是否落在城市边界内、必填字段是否有空值。坐标越界是最常见的异常,原因可能是坐标系不匹配或者检索串城了。我一般会用城市的外接矩形做快速过滤,明显在框外的直接标记异常,不进入主表。这一步能拦掉大部分脏数据,减轻后续清洗压力。
4. 坐标转换与字段标准化实操
4.1 坐标系识别与转换方法
坐标系转换是POI处理里绕不开的一环。前面提过国内常见的三种坐标系,实际拿到数据时第一步是判断它属于哪种。判断方法有几个:看数据来源说明(最可靠)、看坐标数值范围(经纬度大致能判断是否在国内)、拿几个已知地标做比对(把记录坐标和地标真实位置对比,偏移量能反推坐标系)。
转换本身有成熟算法,WGS84和GCJ02之间的转换是公开的偏移算法,GCJ02和BD09之间也有固定公式。实操时我建议直接用现成的转换库,别自己手写公式,手写容易在边界情况上出错。转换时要注意批量处理和精度保留,坐标保留六位小数基本够用,再多就是噪声了。
注意:转换是有损的,来回转多次会累积误差。所以流程设计上应该“一次转换到位”,采集后立刻统一到目标坐标系,后续所有环节都用统一坐标,不要再反复转。
转换完一定要做抽样验证。随机抽几十个点,在地图上人工核对位置,确认偏移在可接受范围内。我遇到过转换库版本问题导致整体偏移的情况,抽样验证十分钟就能发现,不做的话可能整批数据白跑。
4.2 类别映射表的建立与维护
不同来源的类别体系不一样,合并前必须做映射。我的做法是建一张映射表,左列是来源类别原文,右列是目标类别编码,中间加一列备注说明映射理由。映射表要版本化管理,每次调整都留记录,因为映射规则会随着分析需求变化而调整,没有版本管理后面根本说不清哪版数据用了哪版规则。
映射的难点在模糊地带。比如“美食城”到底算餐饮还是算商业综合体,不同分析目标下答案不同。我的处理原则是:优先按主要功能归类,拿不准的单独设一个“混合类”,不要硬塞进某个类别,否则会污染该类别的统计结果。混合类的记录在分析时可以单独看,也可以按需拆分,灵活性更高。
映射表建好后要做覆盖率检查,看有多少记录没被映射到。未映射比例高说明映射表不全,需要补充;比例低但有集中出现的未映射类别,说明这些类别值得单独处理。这个检查我一般每批数据都跑一次,当成质量门禁。
4.3 地址与行政区划的规范化
地址字段的脏数据特别多,常见问题包括:缺区县、区县名简写、地址里混入电话、同一地址多种写法。规范化第一步是补全行政区划,用坐标反查所在区县是最稳的方法,比解析地址文本可靠得多。反查需要区划边界数据,这个可以从公开渠道获取。
地址文本清洗我一般做几件事:去掉明显的非地址内容(电话、营业时间片段)、统一“路/街/大道”等后缀写法、把“省市区”层级拆成独立字段。拆层级的好处是后续按区县聚合时不用再做字符串解析。拆的时候用规则匹配加人工抽检,纯规则容易在特殊地名上翻车,抽检能兜住大部分问题。
行政区划编码建议统一用国家标准编码,六位数字那种。用编码而不是名称做关联,能避免名称变更和同名问题。编码字段在合并全国数据时尤其重要,它是跨城市数据能对齐的基础。
5. 数据清洗与质量校验的实战细节
5.1 去重策略:同名不等于同店
去重是POI清洗里最容易做错的一步。简单按名称去重会误杀,因为不同城市同名店很常见,同城不同分店也可能同名。我的去重逻辑是分层的:第一层按“名称+坐标距离阈值”判断,坐标非常接近且名称相同的视为重复;第二层对名称相同但坐标有距离的,结合地址和类别再判断;第三层保留疑似重复但不确定的,打标记不删除。
距离阈值的选择要看数据精度。如果坐标精度在几十米级别,阈值设一百米左右比较合理;精度差的数据阈值要放大。阈值设太小去不掉重复,设太大又会误合并。我一般先用样本数据画一下同名点的距离分布,看分布拐点在哪,再定阈值,比拍脑袋靠谱。
还有一种重复是跨来源重复。同一个地点从两个来源各采到一条,字段略有差异。这种合并时要做字段融合,原则是:坐标取精度更高的来源,名称取更规范的,类别按映射表统一后取更细的,扩展字段取非空的。融合规则要写清楚,不然合并结果没法复现。
5.2 异常点识别与处理
异常点主要有几类:坐标越界、坐标落在水域或山体等不可能有POI的区域、类别与名称明显矛盾、地址与坐标所在区划不符。识别方法上,坐标越界用边界框过滤;落在水域用土地利用数据或简单的水系掩膜做叠加判断;类别矛盾可以用关键词规则做初筛,比如名称含“加油站”但类别是“餐饮”的拎出来人工看。
处理异常点不要一刀切删除。我的做法是分级:确定错误的直接删或修正;疑似错误的打标记保留,分析时可按需排除;无法判断的单独存一张待核表,积累多了集中处理。一刀切删除的风险是把正确数据误删,尤其是边界附近的点,坐标稍微偏一点就出界了,但地点本身是真实的。
提示:异常点比例是衡量数据质量的重要指标。正常情况下一批数据的异常率应该在个位数百分比,如果异常率很高,优先怀疑坐标系或采集范围出了问题,而不是逐条去修。
5.3 完整性校验与覆盖度评估
完整性校验看两个维度:字段完整度和空间覆盖度。字段完整度统计各字段的非空率,核心字段(名称、坐标、类别、区划)非空率应该接近百分之百,扩展字段可以放宽。空间覆盖度是把采集到的点按网格统计密度,看有没有明显空洞。空洞可能是采集遗漏,也可能是该区域确实没POI,需要结合卫星影像或实地情况判断。
覆盖度评估我习惯做一张网格密度图,直观看出哪里密哪里疏。城市中心密度高是正常的,但如果某个建成区网格密度为零,就要回头查采集日志,看是没采到还是采了没数据。这个检查在多城市批量项目里特别有用,能快速定位哪个城市的哪个区域需要补采。
6. 常见问题排查与避坑经验
6.1 采集阶段的典型故障
采集阶段最常见的问题是返回结果突然变少或变空。排查顺序我一般是:先看请求参数有没有变(关键词、城市、网格范围),再看返回状态码和错误信息,然后拿单个已知有数据的网格做对照测试。如果对照测试正常,说明是特定网格或关键词的问题;如果对照也异常,可能是服务端限制或参数整体出了问题。
另一个高频问题是分页拉取时数据重复或遗漏。重复通常是分页参数没处理好,比如页码从零开始还是从一开始搞混了;遗漏可能是采集过程中数据有增删导致分页错位。应对办法是尽量用稳定的排序字段做分页,或者干脆用网格切分代替深度分页,后者更稳。
6.2 数据合并后的对不齐问题
多城市数据合并后经常出现“对不齐”:同一个连锁品牌在不同城市记录的名称写法不同、类别编码不同、坐标精度不同。这不是采集错误,是来源本身的差异。解决办法是在合并前先做一轮全局标准化,名称做去空格和统一全半角,类别走统一映射表,坐标统一精度。标准化规则要写成可执行的脚本,每次合并都跑,别靠手工。
还有一种对不齐是时间维度上的。不同城市采集时间不同,数据新鲜度不一致,合并后做同比分析会失真。我的处理是记录每个城市的采集时间,分析时按时间分层,或者只取时间窗口接近的城市做对比。这个细节在报告里要写清楚,不然结论容易被质疑。
6.3 问题速查表
| 现象 | 可能原因 | 排查动作 | 处理方式 |
|---|---|---|---|
| 返回结果为空 | 关键词无匹配/网格无数据/被限流 | 换已知有数据的网格对照测试 | 调整关键词或网格,限流则暂停 |
| 点位整体偏移 | 坐标系不统一 | 取地标点比对偏移量 | 统一转换到目标坐标系 |
| 同名点大量重复 | 去重阈值过小/跨来源重复 | 看同名点距离分布 | 调整阈值,做字段融合 |
| 某区域密度为零 | 采集遗漏/网格切分错误 | 查采集日志和网格覆盖 | 补采该区域 |
| 类别统计异常 | 映射表不全/类别矛盾 | 查未映射比例和矛盾记录 | 补映射表,人工核异常 |
| 合并后条数对不上 | 去重误杀/分页遗漏 | 对比去重前后和分页日志 | 修正去重逻辑,改网格切分 |
这张表是我这些年排查问题的浓缩,实际遇到时按现象对号入座,能省不少时间。但要注意,同一个现象可能有多个原因,排查要按从简到繁的顺序来,先排除参数和限流这类简单原因,再深入数据层面。
7. 批量项目的组织与效率优化
7.1 分批次与优先级安排
多城市项目最忌一上来就全量跑。我的习惯是先跑一个中等规模城市做全流程验证,从采集到清洗到校验走通一遍,确认流程没问题再铺开。铺开时按城市等级分批,一线和新一线先跑,因为数据量大、问题暴露早,早发现早调整;中小城市后跑,流程已经稳定,跑起来快。
批次之间留出间隔,一方面给限流留缓冲,另一方面给自己留出检查时间。每批跑完做一次快速质检,看条数、异常率、覆盖度是否正常,正常再跑下一批。这个节奏看起来慢,但比一口气跑完再发现系统性问题要快得多,返工成本低。
7.2 日志与可追溯性设计
日志要记到能复现的程度。每个请求记录时间、参数、返回状态、返回条数;每个网格记录开始和结束状态;每个城市记录汇总统计。日志按天或按批次切分,别写成一个巨大文件,查起来费劲。关键节点打上标记,比如“城市X类别Y网格Z完成”,方便快速定位。
可追溯性还体现在数据版本上。每批数据落盘时记录采集时间、使用的映射表版本、转换脚本版本。后面发现数据问题,能顺着版本信息查到是哪一版流程出的问题。这个习惯在多人协作时尤其重要,没有版本信息,出了问题只能互相猜。
7.3 效率与成本的平衡
效率优化有几个方向:减少无效请求、提高单请求信息量、并行但可控。减少无效请求靠网格和关键词的合理设计,前面说过。提高单请求信息量靠选对返回字段,不需要的字段别请求,能减少传输和处理开销。并行要控制并发数,并发太高容易触发限制,我一般从低并发开始试,稳定后再逐步加。
成本方面,如果用的是有配额的服务,要把配额花在刀刃上。我的做法是先粗后细:粗粒度先扫一遍全城,拿到大致分布,再对重点区域做细粒度补采。这样配额利用率高,也不会在无关区域浪费请求。免费或开放来源则主要考虑时间成本,批量脚本跑起来后人工干预越少越好。
8. 数据交付与后续维护
8.1 交付格式与文档配套
交付不只是给数据文件,还要给配套文档。文档至少包含:字段说明(每个字段的含义、类型、取值范围)、坐标系说明、采集时间、覆盖范围、已知问题。字段说明要写到别人不看代码也能理解的程度,尤其是类别编码,要给完整的编码对照表。
数据格式我一般给两种:一种是便于程序处理的结构化格式,一种是便于人工查看的表格格式。两种格式内容一致,只是组织形式不同。交付前做一次完整性检查,确保两种格式条数一致、字段一致,别出现格式转换丢字段的低级问题。
8.2 更新机制与增量采集
POI数据是有时效的,交付不是终点。如果项目需要持续使用,要设计更新机制。全量重采成本高,增量采集更现实。增量的思路是:保留上一版数据,新采集的数据和旧数据做比对,新增的标记为新增,消失的标记为可能关闭,变化的标记为更新。比对逻辑和去重逻辑类似,但要多一个时间维度。
增量采集的频率取决于数据变化速度和分析精度要求。商业类POI变化快,季度更新比较合理;公共服务类变化慢,半年或一年更新一次也行。更新时注意保持字段结构和编码体系不变,否则新旧数据没法合并。
8.3 合规使用的边界意识
最后必须提一下合规。POI数据涉及地点信息,采集和使用都要在允许的范围内。使用公开服务时遵守其使用条款,不超量、不滥用;使用开放数据时遵守其开放协议;数据里如果包含联系方式等个人信息,要按相关规定处理,不做超范围使用。这些不是套话,是实际项目里必须守住的底线,越界带来的麻烦远大于数据本身的价值。
我在实际项目里的体会是,POI采集这件事,技术门槛其实不算高,真正拉开差距的是流程设计和质量意识。同样的工具,有人跑出来的数据能用,有人跑出来的数据一堆坑,差别就在有没有把坐标系、去重、校验这些“脏活”做扎实。另外一个小技巧:每做完一个城市,把遇到的问题记一笔,攒成自己的检查清单,下个项目开工前过一遍,能避开大部分重复踩的坑。这个清单比任何教程都值钱,因为它是你自己踩出来的。