ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

开店选址调研:用地图 API 做竞对密度盘点

开店选址调研:用地图 API 做竞对密度盘点 开店选址调研:用地图 API 做竞对密度盘点开奶茶店、咖啡店、健身房之前,谁都想知道一个问题:这条街上已经有多少家同行了?传统做法是踩点、数铺、问中介,一天能看两条街。用地图 API 可以一晚扫完半个城区,而且结论是可复算的——同一个坐标、同一个缩放级别,下个月再跑一遍还能对比。这篇给一个竞对密度盘点脚本:划定候选区域网格 → 逐格采集同行 → 按网格统计密度 → 输出一张能直接贴进选址报告的 CSV。参数与字段以 SerpBase 官方文档的 maps/search 端点说明 为准;每次成功请求 2 credits,动手前先把成本算清楚。为什么用网格而不是一个城市中心点选址调研最容易犯的错:拿城市中心点 一个大范围搜一把,看到全城 300 家咖啡店,然后呢?这个数字对选址毫无意义——你要知道的是候选铺位周边 500 米有几家。所以做法是网格化:把候选区域切成若干格,每格用中心点 zoom圈定范围单独采集,统计落在每格里的同行数量。哪格密度低、哪格密度高,一张表看清楚。文档里lat/lng是可选参数但必须成对发送,zoom取值 1-21、传坐标时默认 14——这两条决定了你的网格设计:zoom 决定单格覆盖范围。zoom 14 约是区县尺度,适合初筛;锁定候选商圈后用 zoom 15/16 细看。步长(相邻格中心点的距离)和 zoom 要配套。网格重叠会重复计门店(浪费 credits),网格有缝会漏门店。宁重叠勿留缝——反正按feature_id去重。密度盘点脚本importcsv,json,pathlib,requests APIhttps://api.serpbase.dev/google/maps/searchKEY你的 API KeyHEADERS{X-API-Key:KEY,Content-Type:application/json}defgrid_centers(center_lat:float,center_lng:float,rows:int,cols:int,step_deg:float):以中心点为中心生成 rows×cols 的网格中心点。r0,c0(rows-1)/2,(cols-1)/2foriinrange(rows):forjinrange(cols):yield(round(center_lat(i-r0)*step_deg,6),round(center_lng(j-c0)*step_deg,6))deffetch_cell(q:str,lat:float,lng:float,zoom:int)-list:resprequests.post(API,headersHEADERS,json{q:q,lat:lat,lng:lng,zoom:zoom},timeout30)dataresp.json()ifdata.get(status)!0:raiseRuntimeError(f{lat},{lng}:{data.get(status)}{data.get(error)})returndata.get(places,[])defdensity_survey(q:str,center_lat:float,center_lng:float,rows:int3,cols:int3,step_deg:float0.015,zoom:int15)-list:逐格采集竞对,按 feature_id 去重后统计每格密度。grid_dirpathlib.Path(scout_grid)grid_dir.mkdir(exist_okTrue)cells,seen[],set()foridx,(lat,lng)inenumerate(grid_centers(center_lat,center_lng,rows,cols,step_deg)):cachegrid_dir/fcell_{idx}_{lat}_{lng}.jsonifcache.exists():placesjson.loads(cache.read_text(utf-8))else:placesfetch_cell(q,lat,lng,zoom)cache.write_text(json.dumps(places,ensure_asciiFalse),encodingutf-8)fresh[]forpinplaces:fidp.get(feature_id)iffidandfidnotinseen:seen.add(fid)fresh.append(p)cells.append({格号:idx,格心纬度:lat,格心经度:lng,竞对数量:len(fresh),平均评分:(round(sum(p[rating]forpinfreshifp.get(rating))/max(1,len([pforpinfreshifp.get(rating)])),2)),代表商户:、.join(p[name]forpinfresh[:3]),})returncellsif__name____main__:# 示例:以某商圈为中心扫 3×3 格,找奶茶店cellsdensity_survey(奶茶店,31.2304,121.4737,rows3,cols3,step_deg0.015,zoom15)totalsum(c[竞对数量]forcincells)withopen(scout_density.csv,w,newline,encodingutf-8-sig)asf:wcsv.DictWriter(f,fieldnameslist(cells[0].keys()))w.writeheader()w.writerows(cells)print(f9 格共{total}家竞对 → scout_density.csv)forcincells:bar█*c[竞对数量]print(f格{c[格号]}:{c[竞对数量]:3}家{bar}(均分{c[平均评分]}))三条选址判读经验密度要分类目看,别只看总数。300 家咖啡店里 250 家是连锁(星巴克、瑞幸),50 家独立店——对独立店选址者来说,真正的竞争信号是后者。脚本采回来之后,按名称把连锁品牌摘出来单独统计:连锁密度高的区域说明市场被验证过、但也说明点位被占得狠;独立店密度低 连锁也少的格,才可能是空白市场。评分分布比数量更早暴露问题。某格竞对数量中等,但平均评分只有 3.6,而其他格普遍 4.3——这通常意味着这个格的服务/产品供给有问题(或者数据里混进了加油站便利店)。反过来,高密度 高评分并存,说明这里是成熟商圈,拼的是差异化不是空白。先小网格试跑,再放大。第一晚先跑 1×1 或 3×3,看看你选的城市层级、品类词返回的密度。咖啡店在上海核心区一格可能 40 家,在二线城市一格 5 家——密度差一个量级,你的步长和 zoom 就得重新配。不要第一晚就上 5×5,2 credits 一格,25 格就是 50 credits,配错了参数等于白烧。成本账每格一次请求 2 credits:3×3 试跑 18 credits,5×5 放大 50 credits。想覆盖全城按 10×10 算就是 200 credits——$10/20k 的标准包够跑好几个城区,但请先算行×列×品类数×轮次再动手。如果还要对入围竞对拉详情(营业时间、电话、地址),每店再 2 credits,10 家入围就是 20,采集前先按名单筛一轮,别对网格里所有商户无脑拉详情。FAQ为什么返回里找不到评价数字段?地图结果的字段里只有rating(评分),没有评价数(没有 review_count 字段)。所以口碑分析用评分分布做,别承诺按评价量排序——文档化载荷里没这个数。想要评价量得换数据源。候选点位怎么从网格落到具体铺位?网格给的是区域级密度结论(哪几格值得实地看),不是铺位推荐。把密度最低的 2-3 格连同代表商户列一起交给线下踩点,线上排查 线下验证,比纯线上或纯线下都快。多久复跑一次对比?建议按月。每次复跑用完全相同的中心点、步长、zoom 和查询词,结果另存为带月份的文件,然后对比竞对数量和平均评分两列的变化。数量持续上涨说明商圈在升温(租金也会),评分下滑说明供给质量在稀释——这两个信号比任何中介的话都实在。中文品类词要处理编码吗?不用,JSON body 直接传 UTF-8,请求头带Content-Type: application/json即可。先跑 3×3 拿一张密度热力图,再决定去实地看哪几格——这就是用地图 API 做选址初筛最省钱的打开方式。
返回列表