这两年做城市分析相关项目时经常被问同一个问题“能不能把高德城市最新POI拉一份再弄一版历史POI列表做对比”问的人里有做门店选址的、做商圈研究的、做城市规划评估的还有想复盘某个连锁品牌扩张节奏的。大家的需求其实很一致最新POI用来看现状历史POI用来看变化。这两者叠加在一起就是一套能观察城市商业演变的“时间序列数据”。这篇文章我不会讲任何灰色渠道的东西也不涉及任何绕过鉴权的办法。我只用公开可申请的开放平台能力把“高德城市最新POI”跑通再告诉你“高德历史POI列表”应该怎么积累、怎么用。无论你之前是否接触过地图数据只要会一点Python按下面的思路走3到7天就能搭出属于自己的城市POI快照系统。先说清楚一件事在地图服务里POIPoint of Interest指的是兴趣点也就是地图上那些有名字、有坐标、有地址的点——餐厅、酒店、商场、小区、学校、加油站统统算。一个城市最新POI列表意味着你抓到的每一个点都能反映此刻地图上的真实状态。而“历史POI列表”则是这些点在某个过去时间点的状态快照。理解了这两者的关系后面所有的操作都顺理成章。1. “最新历史”这个组合需求是从哪冒出来的1.1 两类数据分别决定“看什么”和“怎么变”很多新手一上来就问“怎么爬POI”但这其实是个伪需求。真正的需求通常是我想知道某个行业在某个城市怎么分布的或者我想观察某个品牌门店在近一年的扩张和收缩情况。这两种问题恰好对应了两类数据的不同价值。“高德城市最新POI”回答的是空间问题今天、这个时刻哪些地方有什么。你拿来做密度分析、选址对比、商圈画像用的就是最新目录里的点。比如你想在东部某个三线城市开一家咖啡馆你需要知道这家城市当前有多少家咖啡馆、它们集中在哪些街道、周边有没有同类竞品——这个数据必须新鲜过期三个月都可能误判。“高德历史POI列表”回答的则是时间问题某一段时间内地图上的点发生了哪些变化。某个区域新增了哪些门店、原有门店是否消失、是否有商家改名或搬迁。如果把最新数据比作一张照片历史数据就是相册里按时间排好的旧照片。只有把照片按顺序翻过去才能看到城市商业变化的完整过程。1.2 谁在用这套数据组合我接触到的使用者大致分几类。第一类是零售和连锁行业的朋友。某连锁茶饮品牌要进一个新城他们会在当地拉全部同类品牌的门店POI同时看过去两年这些门店的新增和关闭情况以此判断市场饱和度。第二类是做地理空间研究的学生和研究者。他们需要POI来量化城市功能区的演变某个老的工业区是不是变成了餐饮聚集区大学城旁边的酒店数量为什么逐年下降这类研究如果只有最新数据就只能做横截面分析加上了历史数据才能做纵向对比。第三类是房产和物业方向的从业者。看一个小区周边的POI增减能辅助判断社区成熟度、生活配套完善度甚至用来给楼盘撰写周边配套说明。这三类人的共同痛点很一致最新数据好拿历史数据不知道怎么搞。这也是为什么“高德历史POI”这个关键词搜索热度一直很高——因为大部分人都卡在这一步。2. 官方平台API是拿“最新POI”的正道2.1 公开接口的能力边界说到高德城市最新POI最正规的路径就是走官方开放平台的Web服务API。你注册为开发者后会拿到一把专属的Key用它来调用接口。公开接口有两种常用检索方式关键字搜索和周边搜索。城市维度的数据拉取通常用关键字搜索把城市编码传进去再指定一个关键词比如“酒店”“咖啡”“药店”。要注意官方接口不是让你一次性下载全量数据的。它的定位是“按需检索”就是你提一个明确的关键词和一个明确的城市它返回匹配的那批点。所以“高德城市最新POI”这个需求落到实际操作上应该拆分成一个矩阵城市 × 关键词。你先把城市确定下来再把所有你想关注的行业词穷举出来逐个请求、逐页拉取、逐份存档。2.2 请求参数里最容易忽略的细节以关键字搜索为例HTTP请求的几个主要参数如下key你的开发者Keykeywords搜索关键词比如“便利店”city城市编码如杭州对应330100注意是区划码不是城市拼音offset每页返回的记录条数最大能设到25page页码从1开始extensions取值为base或allall会返回更详细的字段比如营业时间、联系电话、评分等但消耗配额也多。这里有一个我反复踩过的坑很多同学只传了keywords和city忽略了citylimit参数。如果不指定城市范围限制接口在匹配不到足够结果时会把周边城市的同类POI补进来导致你拿到的是“区域结果”而不是“城市结果”。所以一定要加上citylimittrue强制只返回当前城市的数据。另一个细节是关键词的粒度。拿“美食”做关键词返回的是大餐饮类目拿“火锅”做关键词返回的是火锅店。不同粒度的词在type字段上会体现为不同层级的分类。我的习惯是先做一份“行业关键词表”一个细分行业至少对应三到五个词抓完再合并去重覆盖率比单个词高很多。2.3 回包字段与解析思路接口返回的是JSON结构通常长这样{ status: 1, pois: [ { id: B000A8XXXX, name: 某连锁咖啡店, type: 餐饮服务;咖啡厅;咖啡厅, location: 120.123456,30.123456, address: 某某路12号, pname: 浙江省, cityname: 杭州市, adname: 西湖区 } ] }解析的时候我建议重点保留以下字段字段说明用途id平台内部POI唯一编号后续做历史对比的主键候选name店铺或地物名称展示与分析location经度,纬度空间分析type三级分类用分号分隔行业归类pname/cityname/adname省、市、区名称行政区划过滤address详细地址数据去重辅助解析时不要把type当字符串直接存我记得某次分析“餐饮”类时发现光“餐饮服务;中餐厅;烤鸭店”和“餐饮服务;中餐厅;川菜”这两类写法就有一堆分支。正确做法是先把type按分号拆成列表存一列同时把第一级、第二级单独拆列方便后面聚合。2.4 配额、翻页与并发策略公开接口每天的调用配额个人认证一般是限额的企业认证较高。单次请求最多返回25条所以一旦检索结果超过25条就必须翻页。但翻页不是无限翻的接口对单次检索的总页数有上限一般到几百条左右就会停下来。这意味着一个城市的关键词如果匹配到上万条POI靠单关键词分页是拿不全的。解决思路有两种。一是把关键词拆细不搜“餐饮”改搜“火锅”“烧烤”“面馆”“甜品”等细分词。二是按行政区拆分在城市编码的基础上再把city参数替换成区编码逐区抓取。这两种方法可以叠加使用也是我做“高德城市最新POI”全量数据时最常用的方案。并发方面我的建议是单线程循环加适当延时。公开接口不是给你做实时爬虫用的盲目开并发很容易触发限流反而把每天的配额浪费在重试上。稳妥的节奏是每请求一次停顿0.2到0.5秒一个城市一个城市地处理。3. 历史POI列表从哪里来快照、存档与合规边界3.1 几乎所有平台都不直接给历史接口这是很多人最头疼的地方。地图开放平台只提供当前的数据状态不会给你一个“2023年6月30日的高德POI列表”按钮。所以“高德历史POI列表”本质上不是一个现成的数据产品而是一种数据积累策略。谁先开始攒快照谁就有历史数据。目前圈子里主流的历史POI来源有三类自己攒的快照、第三方整理的历史存档、平台面向企业提供的行业数据包。第三方存档和行业数据包存在很多来源不明和授权不清的问题我的态度一贯是不要碰——历史数据再值钱也比不上合规风险带来的麻烦。最可控、最适合个人和中小团队的做法就是自建快照。3.2 自建快照的目录设计与采集策略自建快照的逻辑很简单每隔一个固定周期用同样的参数、同样的关键词集合把目标城市的数据完整拉一遍存成带日期的版本文件。我在实际项目中会按这样的目录存poi_snapshot/ 330100/ 2024-01-01/ 酒店.csv 餐饮.csv 咖啡.csv 2024-02-01/ 酒店.csv 餐饮.csv 咖啡.csv文件名带上日期非常关键这能让你后续做回溯对比时一眼就知道这份数据是哪个时间点的。存储格式我一般用Parquet它能压缩、能按列裁剪读取速度快如果你不熟悉CSV也完全能接受只是数据多了之后比较占空间。采集频率怎么定这取决于你的用途。做城市商业分析月度快照就足够如果是盯某个商圈的激烈变动周度快照也行。我不建议做每日全量快照——配额压力大而且POI数据本身变动幅度有限日粒度只会让数据膨胀分析时还要花大量精力去处理轻微抖动。3.3 唯一键设计历史对比的地基既然要做“最新 vs 历史”的对比就必须有一套能识别“同一个点”的方法。最理想的情况是里面有一个POI ID字段只要两次快照中ID相同就可以判定为同一个兴趣点。但现实是平台对POI ID的稳定性和公开程度并非完全可预期而且当你很久以后翻旧文件时某家店可能已经连ID都变了。所以我的做法是在存储每条记录时额外生成一个“业务主键”由城市编码 一级分类 名称 地址拼接而成。为了提高匹配覆盖率名称要做归一化把括号、空格、减号、大小写统一处理。这样即使某条记录的原始ID失效了我还能靠业务主键做模糊关联把历史档案和最新状态对齐。有一点必须提前想明白同一家店去年叫“老王面馆”今年改叫“老王面馆旗舰店”业务主键就不匹配了。没有完美的自动方案我能做的是在对比分析时把“编号匹配失败但名称高度相似”的记录单独筛出来让人工判断。这个环节很土但很管用。3.4 数据红线哪些历史数据不能碰这里必须把合规边界讲清楚。地图数据涉及测绘地理信息国家对地理信息数据的采集、存储、传播有严格管理规定。个人开发者通过官方接口获取数据应当在许可范围内使用不能自行打包转售也不能把数据用于违法犯罪活动。至于那些“一库在手、全网历史POI随意下载”的渠道我强烈建议直接划清界限因为这类数据很可能涉及未授权采集、个人信息泄露或非法测绘使用它会给自己和团队带来不可控的法律风险。合规但不慢的路径是有的先确定自己的分析目标然后为了这个目标去申请合适配额、正常调用接口、持续存档。你现在开始攒快照三个月后你就有三个月的历史数据你不动手三个月后你依然什么都没有。历史数据说到底是最朴素的时间复利。4. 把最新和历史放一起做对比一套可复现的分析思路4.1 数据对齐前的清洗步骤拿到最新POI和历史快照之后先别急着分析。第一步是清洗对齐这一步做不好后面全白干。我通常按这样的流水线处理把两份数据都读进来统一列名和字段类型去掉纯空行、纯空值的记录按“业务主键”去重同一快照里只保留一条把type字段拆成一级分类、二级分类、三级分类三列检查location字段丢掉的坐标用地址兜底无法解析的单独存到异常表。清洗时要注意最新POI和旧快照之间的口径不一定完全一致。比如某个平台接口某次升级后分类字段的层级写法出现变化直接对比就会误判成“大量新增或消失”。所以每次换接口版本后我都建议单独做一个字段版本检查把新旧口径的差异先识别出来再决定是否合并。4.2 变化分类新增、消失、搬迁、字段变更清洗完把两份数据按主键关联就能给每条记录打标签了标签判断条件业务含义新增最新快照存在历史快照不存在新店开张、新点上线消失历史快照存在最新快照不存在关店、闭点、下线保留两边都存在且主要字段一致没有显著变化变更两边存在但名称或地址变动改名、装修、搬迁这个四分类看着简单实际运行起来会有一些有趣的发现。比如某个城市的酒店数量在一个季度内“消失”了300家但仔细一看其中有相当多是名称规范化造成的——原来“某某大酒店”改成了“某某酒店”本质是同一家店。这种误判不可避免但可以通过把“名称编辑距离很小”的消失记录拿出来复查来改善。4.3 具体案例用快照追踪一个地级市的连锁餐饮变动我用一个模拟场景来说明整套流程。假设目标是中部某地级市的连锁火锅品牌。我先在2024年的最新POI里用“火锅”关键词拉取全城数据再取一份半年前的快照然后做对齐。半年前有420家火锅类POI这次最新快照变成了505家。按坐标和ID匹配后新增96家消失81家约390家是两边都存在的。再往下拆新增的96家里有十几个点位于同一个新建商圈。这说明市场的增量主要集中在新商圈。消失的81家里有相当一部分是老城区的社区底商原址上没有新店接替。这个结果对一个餐饮投资分析来说比单纯看“总数涨了85家”有价值得多——它告诉你变化发生在哪里、为什么发生。我把统计结果做成下面这样的汇总表区域半年前数量最新数量新增消失净变化老城区1481391019-9高新区10214136739大学城片区96118281117滨江新城7410722418这一组数据能马上告诉你火锅店的扩张和收缩在不同片区呈现完全不同的方向。如果你只看“最新POI列表”你只会觉得高新的店很多但加上历史对比你才能看到它是“从老城转移过去的增量”还是“老城消失带来的回流”——这决定了市场和迁址策略的判断。4.4 可视化和汇报建议做完对比下一步通常是出图。画图时有几个值得注意的地方。坐标系统一用平台返回的坐标不要直接和GPS轨迹叠加因为两者坐标基准不同直接叠加会看到位置偏移。展示变化时我建议用三张图第一张是新增POI点密度图第二张是消失POI点密度图第三张是变化前后的热力对比图。这样能把“哪里有新增”“哪里在消失”“净变化如何”拆开表达而不是混在一张图上让人猜。5. 我踩过的坑和每天要留意的事5.1 翻页上限数量大的关键词抓不全前面说了单次检索有页数上限这里再补充一个真实场景。某次我抓一个一线城市连锁药店的数据关键词“药店”市区内匹配结果上万条。结果我翻到第几十页的时候接口返回的pois越来越稀最后直接给了一个空数组。排查了一下症结不在代码而在接口单次关键词检索的总条数上限。解决通道就是拆分。后来我把全城拆成各下辖区又按“药店”“连锁药房”“大药房”等词拆分跑完合并数据量才真正对齐实际规模。这里提醒一句任何你从地图上肉眼看到的“全城300家药店”靠单个关键词分页都不一定能完整抓下来拆词、拆区才是正解。5.2 配额每天就那么点量要省着花个人开发者配额有限一次全量抓取可能消耗掉好几天的量。所以我在做“高德城市最新POI”批量任务时会把计划拆成分片任务比如按城市和关键词两两分组设定一个每天抓取上限。一个额外的技巧是先用base模式跑快速摸底确认哪些关键词返回量少、哪些返回量巨大再决定哪些词需要深化抓取。不要一上来就对所有关键词用all模式那样配额几天就见底了。5.3 坐标“看起来偏了”可能不是数据问题地图数据返回的坐标是经过坐标偏移算法处理的和真实GPS坐标存在差异这是地图产品通用的合规处理方式不是接口故障。如果你拿这个坐标和手机GPS坐标在同一个坐标系直接叠加会看到几十米到几百米的偏差。我在项目里习惯统一用平台坐标做分析不做任何纠偏所有点位相对位置是自洽的。只有当你要和GPS轨迹、无人机影像融合时才需要做坐标转换那一步要在明确的测绘规范指导下进行。5.4 分类字段层级混乱直接影响统计POI的type字段虽然是三段结构但不同POI的写法并不统一。有些是“餐饮服务;中餐厅;火锅店”有些是“餐饮服务;中餐厅”有些干脆只有一级“道路附属信息”。做分类统计分析时如果直接拿完整字符串分组会得到大量碎片化类别很难看出规律。我的处理方式是把type打散、取第一级或第二级做聚合同时建立一个自定义分类映射表。映射表按业务语料去改写比如凡是一级分类里含“餐饮”的都归到“餐饮”二级分类含“火锅”的再单独打标签。这样既保留了官方分类的层级信息又能在分析时统一口径。5.5 名称规范化同名不同店、同店不同名名称规范化是最脏最累的活儿。两家不同地址的店可能同名同一家店的数据在两个快照里可能写法不同。为了减少误判我维护了一份地址和名称的清洗规则去除全角半角差异、统一大小写、去掉“有限责任公司”“连锁”等通用后缀。举个例子一条记录名称是“某茶饮滨江万达店”另一条是“某茶饮-万达店”这两条其实指向同一家店。我写了一个简单的规则函数把括号和连接符归一化再把末尾的商圈名单独拆成一列。这样在业务主键匹配时匹配率能提升不少。这一套正则其实不难但收益非常直接。5.6 快照不是一次性工作要能回答“这是哪天的数据”最后一定要养成写数据版本属性的习惯。每次存储快照时在文件头部写入采集时间、接口版本、关键词集合的哈希值。很多项目做到后期会发现团队里有人拿了一份两周前的POI数据当作最新数据用源头就是因为文件没有带上清晰的时间戳。我的做法是在每份CSV里增加三列snapshot_date、api_version、keyword_set_version。后续任何对比分析前先检查这两份快照的日期和参数是否可比。数据口径不一致的对比比没有数据更害人。我个人做了快一年的城市POI快照回头看最大的感受就是别贪大求全先从一个城市、一个行业、一个季度开始。把“最新POI”拉准把“历史快照”攒稳等积攒了三个月以上数据你自然会发现变化分析的价值远远超出你的预期。这套流程不需要多高深的技术拼的是耐心和方法。你现在启动三个月后就有第一批真正的“历史POI列表”。