2026/6/19 9:02:44
网站建设
项目流程
西部数据网站空间,单县网站定制,想注册一个做网站的公司好,做网站前端用什么软件突破高德地图数量限制#xff1a;基于四叉树递归的高德 POI 抓取技术
前言
在地理空间数据#xff08;GIS#xff09;抓取领域#xff0c;高德地图#xff08;Amap#xff09;等服务商的 API 接口通常存在严格的返回数量限制。 例如#xff0c;高德的搜索接口虽然强大…突破高德地图数量限制基于四叉树递归的高德 POI 抓取技术前言在地理空间数据GIS抓取领域高德地图Amap等服务商的 API 接口通常存在严格的返回数量限制。例如高德的搜索接口虽然强大但单次请求即便翻页也存在总量限制通常为 800-900 条或 20 页。对于北京、上海或杭州这样 POI兴趣点密集的城市仅靠单纯的翻页无法获取全量数据。根据笔者的测试设置page_num为第9分页的时候POI数据量为25分页1-8的数据量均为25然而当修改参数page_num为10的时候则数量量为0。本文将解读一套基于 Python 与 Shapely 库实现的“动态四叉树递归抓取”方案。该方案完美契合了技术文章《突破高德地图多边形搜索POI数据的数量限制—等大渔网栅格分割法》中的核心思想通过“分而治之”的策略实现了对高密度区域的无遗漏采集。核心痛点与解决思路痛点API 的“天花板”当你请求一个很大的矩形区域例如整个北京市时如果该区域内包含 5000 个“餐饮”POIAPI 只会返回前 800 个。剩下的 4200 个数据会被直接“截断”无论你如何调整page_num都无法获取。解决思路递归分裂Divide and Conquer参考文章中提到的核心算法如下探测尝试请求当前区域的数据。判断如果数据量达到 API 返回上限溢出说明当前区域过大数据过密。分裂将当前矩形切割成 4 个相等的子矩形左上、右上、左下、右下。递归对这 4 个子区域重复上述步骤直到数据量未溢出或达到最小面积限制。代码实现深度剖析为了实现这一逻辑我首先需要知道一个城市的轮廓图的坐标。我已经收集了全国所有城市的轮廓坐标信息这个不再赘述。我 在几何计算上引入了Shapely库进行优化。以下是关键模块的解读1. 宏观调度初始网格化 (Initial Grid)在run方法中代码并没有直接把整个城市丢进递归函数而是先做了一次粗粒度的切分# 初始网格大小 (千米)INITIAL_GRID_KM100# ...whilecurr_lonmax_lon:whilecurr_latmax_lat:# 生成 100km * 100km 的大网格self.fetch_recursive(...)解读这是一个很好的工程实践。虽然递归可以处理所有情况但先将巨大的城市切割成若干个 100km 级别的区块可以减少单次递归栈的深度同时方便断点续传和并行处理如果未来扩展的话。2. 核心引擎递归与溢出检测 (fetch_recursive)这是整个脚本的灵魂所在。A. 空间裁剪优化 (Geometry Intersection)参考文章中提到的一个重要优化点是不要请求空白区域。我的代码通过shapely实现了这一检查# 1. 构造当前网格的 shapely 多边形current_boxbox(min_x,min_y,max_x,max_y)# 2. 空间判断如果当前网格跟城市轮廓完全不相交直接跳过ifnotself.city_geometry.intersects(current_box):return技术亮点在递归过程中网格会切得非常细。如果不加判断通过矩形切割会产生大量位于城市边缘但在城市轮廓GeoJSON之外的网格例如海面、荒山。通过intersects判断如果网格在边界外直接return极大地节省了 HTTP 请求次数和 API 配额。B. 溢出判断逻辑 (Overflow Detection)如何知道 API 是否“截断”了数据# 检查是否溢出如果是第 MAX_PAGE_NUM 页且数据填满了 PAGE_SIZE 条ifpageMAX_PAGE_NUMandlen(items)PAGE_SIZE:is_overflowTrueprint(f - [溢出] 区域{coord_param}数据过多准备分裂...)break解读如果设定最大翻页数为 7每页 25 条。如果你能翻到第 7 页且第 7 页还是满的25条这在概率上极大概率意味着后面还有第 8 页数据被丢弃了。这时标记is_overflow True触发分裂机制。C. 四叉树分裂 (Quadtree Splitting)当检测到溢出时代码执行经典的分裂操作ifis_overflowanddepth10:mid_x(min_xmax_x)/2mid_y(min_ymax_y)/2# 递归调用四个子区域self.fetch_recursive(min_x,mid_y,mid_x,max_y,depth1)# 左上self.fetch_recursive(mid_x,mid_y,max_x,max_y,depth1)# 右上self.fetch_recursive(min_x,min_y,mid_x,mid_y,depth1)# 左下self.fetch_recursive(mid_x,min_y,max_x,mid_y,depth1)# 右下这种逻辑能确保无论 POI 多么密集例如市中心的商圈网格都会自动细分到足够小例如 50米 x 50米直到能一次性把该小格子的数据完全拉取下来。代码与参考文章的异同点特性参考文章思路我的代码实现评价核心算法四叉树递归分割四叉树递归分割一致抓取核心稳固。无效区域过滤提及利用多边形判断使用shapely.intersects优秀利用专业库不仅准确且代码简洁。初始处理直接从最大边界开始先按 100km 切分初始网格我的更好适合处理超大城市或跨城抓取降低了单个递归树的复杂度。坐标系处理未详细描述手动计算经纬度步长够用但高纬度地区需注意经度变形代码中已包含cos(lat)修正。总结我的码是一份非常标准的高精度 POI 采集脚本。它不仅仅是简单的调用 API而是通过几何计算和递归算法解决了数据采集中的“有界性”难题。这种“检测-分裂-再检测”的模式就像显微镜一样在稀疏的郊区使用低倍镜大网格快速扫过在密集的市中心自动切换到高倍镜小网格细致观察。这正是爬虫工程中处理分布不均匀数据的最佳实践。之前分享的几个代码工具好多人在拿到链接后就立马取关实在是令人寒心。因此本篇文章只讲述思路给出关键部分代码不提供全部源码。