Python抓取百度地图POI的那些坑与可用软件及代码
抓取百度地图、高德地图的POI主要有两大类方式,一类是分析地图网页,一类是使用百度、高德提供的POI检索API。本文主要梳理截止2020年9月,调用百度地图Place API抓取POI数据的那些官方文档没有言明的坑,并给出解决思路。最后提供完美避过这些坑的POI抓取软件和封装好的代码(基于Python实现)。
1 坑与解决思路
- 你以为返回数据上限真的是文档中说的400吗?
天真的少年哦,大概几个月前,还真是,如果数据量超过400,百度的API老老实实给你返回够400条。这个时候,你只需要保证每个切片抓的POI数据在400以内,就可以绕过所谓的"400"限制。然而,百度最近改反扒机制了,但并没在开发者文档中进行说明(直接导致目前超多代码和软件查全率跳楼式下跌最近百度加入了新的抽稀机制,如果你的POI数量达到了一两百乃至更多,则返回的数据会抽稀至100多点或左右,具体抽稀至多少还不是一个定值,总是飘忽不定。
【解决方案】:经过大量测试,确保每次调用百度地图Place API返回的数据量在100以内,在当前能确保到一个极高的查全率。用高德的小伙伴哟,高德的这个阈值设为850可以取得很好的效果哦-虽然高德的数据更全,但高德真的太容易被封了。 - 抓取过程中存在数据模板不一致!!!
目前最经典的数据模板不一致就是查询省(湖北省)和跨市级(西安外接矩形)的POI总量时,API返回的是各个城市分别有多少POI而不是POI的具体信息。比如咸阳市、渭南市与西安太近,且被西安半包含。

在实践中,少量内陆城市如西安及大量沿海城市如福建等,在进行网格切片时会发现部分跨城市区县或涉海域切片Place API返回的是单独某个城市POI的对应切片区域总量,比如上下两图中较小红色框标出的区域。

上述机制会使得你在进行进行网格切分抓取POI的时候易报错。该问题不解决则你无法用同一套代码顺滑的抓取全国任意区域的POI。
【解决方案】:当出现数据模板不一致时(判断results 数组中是否有location)进一步对当前切片进行四分即可。 - 跨城市区县的选择性返回问题
当一个切片跨越两个或多个城市的不同区县级行政区时(但小于整个城市),可能只返回其中一个占据主导地位的城市的对应区县内的POI数据。
这会造成在按格网抓取的时,部分区域可能存在非正常的稀疏或空洞。

【解决方案】:1. 增大格网数量(简单方式,但依然存在少量数据因为边界问题丢失);2. 确保城市边界上的切片(格网)中,希望查询的城市占据主导地位(最佳做法是将格网与行政区划求交后再取最小外接矩形)<建议使用该方法>。
把上述三大问题解决好,你的程序就可以高查全率搞定百度POI的抓取了。具体抓取算法小O取名为:边界修正格网条件四分递归。
2 完美避坑的POI抓取软件 (桌面端)
不想写代码的小伙伴了解一下开源免费POI抓取软件OSpider,抓POI舒服的不要不要的,还有完善的用户社群和用户手册。项目主页或下载戳这里
OSpider v3.0.0桌面版的核心功能为按行政区划名称、矩形框、圆形区和自定义面文件四种方式抓取POI(暂仅支持百度POI,高德POI将再下一次更新中加入),支持通过csv批处理文件批量执行POI抓取任务,且提供了分城市获取POI总量的实用工具。OSpider v3.0.0也集成了WGS84/BD09/GCJ02坐标互转工具与地址解析工具。

3 完美避坑的POI抓取代码(python实现)
GPL开源项目OSpider将POI抓取代码封装在POISpider.py中,该套代码运行稳定调用简单,小伙伴们可以直接在项目主页下载源码自己查看修改或调用,该项目比较好的一点是专门为开发者写了手册。
OSpider v3.0.0源码的功能模块包括POI抓取模块、坐标转换模块、行政区划获取模块、地址解析模块。以下为POI相关调用示例:
from POISpider import BaiduPOISpider
keylist=['YourBAIDUKeySample1','YouRbaiDuKEYsaMPlE2']
spider=BaiduPOISpider()
# key池设置一次就够了,thread_protect是用来限制并发的,表示一个Key最多可以被多少个线程同时占有,只要key不超并发,这个值就可以设置的比较大
# 想速度快,就大key池,多线程,同时在不触发并发限制的情况下调大并发保护数thread_protect
spider.set_key(keylist,thread_protect=3)
#如需在服务器部署,建议取消持续性状态输出用以加快速度,客户端调用建议保留状态输出
#spider.set_dispStatus(False)
#根据行政区划名称抓取POI-抓取广州市内的酒吧
gdf1 = spider.getPOI_byAD('酒吧', '酒吧', '广州', grid_num=4, threshold=100, thread_num=6)
#根据矩形区域抓取POI-抓取西安市外接矩形内的高中(check)
gdf2 = spider.getPOI_byBounds('高中','中学',118.351915,29.192178,120.724682,30.569969, grid_num=4,threshold=100,thread_num=6)
#根据圆形区域抓取POI-抓取上海市政府周边5km范围内的咖啡厅
gdf3 = spider.getPOI_byCircle('咖啡厅','',121.480248,31.236276,5000, grid_num=4,threshold=100,thread_num=6)
#根据自定义面文件抓取POI-抓取福州市内的KTV
gdf4 = spider.getPOI_byFile('KTV', '', 'https://geo.datav.aliyun.com/areas_v2/bound/350100.json', grid_num=4,threshold=100,thread_num=6)
#将结果分别保存为CSV,TXT,Shapefile,GeoJSON
gdf1.to_csv('广州酒吧.csv', encoding='utf-8-sig')
gdf2.to_csv('西安高中.txt', encoding='utf-8-sig')
gdf3.to_file('上海市政府周边5km咖啡厅.shp', encoding='utf-8')
gdf4.to_file('福州KTV', driver='GeoJSON', encoding='utf-8')
抓取结果属性说明
| 列名 | 说明 |
|---|---|
| uid | 唯一标识符 |
| name | POI具体名称 |
| address | POI地址 |
| province | POI所属省份 |
| city | POI所属城市 |
| area | POI所属区县 |
| tag | POI标签(类型) |
| telephone | POI电话,可能为空 |
| overall_rating | POI总体评分,-1表无,5最高 |
| wgs84_lng,lat | WGS84经纬度 |
| bd09_lng,lat | BD09经纬度 |
| gcj02_lat | GCJ02经纬度 |
| geometry | 几何属性 |

本文详细介绍了Python抓取百度地图POI遇到的三大问题及其解决方案,包括数据量限制、数据模板不一致和跨城市区县的选择性返回。推荐使用开源软件OSpider进行POI抓取,该软件支持批量任务和坐标转换工具。同时提供了避坑代码示例。
1933

被折叠的 条评论
为什么被折叠?



