前瞻
地图数据展示了大量不同行业的数据,我们整篇文章以百度地图为例。如下表该表的说明是:
按照这个上面的搜索几乎能把地图所有POI的数据取出。
我们的目标就是当输入几个关键条件就把符合条件的数据全部提取出来。
例如有如下条件
- 经度纬度(可选)
2.城市名称(可选)
3.关键字(必选)
如果我们要搜索北京市范围内的所有教育培训的名称,地址,联系方式(座机/手机) 则有如下解决方案。
方案 利用官方webApi
我们在使用官方WebAPI的POI兴趣点检索的接口的时候,如下接口说明
从图中可以看到几个关键搜索条件
query: 关键字 无需多说
选择方式:地点搜索限定范围可以由region、bounds和location + radius方式进行,其中bounds优先级最高、region优先级最低(与web服务保持一致)
所有有三种范围检索方式,优先级排序是
bounds > location+radius >region
我们查询一下,密钥请替换成 应用类别是<浏览器>的key
http://api.map.baidu.com/place/v2/search?q=教育培训®ion=北京&output=json&ak=你的秘钥&page_size=1000&page_num=1
返回的结果是
{
"status":0,
"message":"ok",
"total":400,
"results":[
{
"name":"国家发展和改革委员会顺义培训中心",
"location":{
"lat":40.093096,
"lng":116.494833
},
"address":"后沙峪镇边河路57号1区",
"province":"北京市",
"city":"北京市",
"area":"顺义区",
"street_id":"161a0ed28daef4495cd4fe3d",
"telephone":"(010)69455888",
"detail":1,
"uid":"161a0ed28daef4495cd4fe3d"
},
{
"name":"鸿基培训中心",
"location":{
"lat":39.855807,
"lng":116.25832
},
"address":"洪泰庄97号",
"province":"北京市",
"city":"北京市",
"area":"丰台区",
"street_id":"63275e84b36988362ce67b6f",
"telephone":"(010)63852093",
"detail":1,
"uid":"63275e84b36988362ce67b6f"
},
{
我们设置的是page_size=1000, 但是total参数告诉我们,一共是400. 我们在北京市的地图上搜索时发现返回的结果是
我们注意到结果数字是 13465个,不过不要着急,这还不是最终结果数,我们继续缩小地图
好了,我们看到北京市教育培训的兴趣点一共有14139个,这才是真正的数量。此时你就算继续缩小地图结果数都不会变的!
那么相比于400个, 14139真的是它的35倍之多,其他关键字搜索也是一样的。那么为什么百度API结果做这种限制呢? 本人认为是防止抓数据,盗取数据太容易。不过咱们也有解决办法。
仔细思考一下,刚才说的一次接口调用,检索最多返回400个结果,而北京市一共有14139个结果,是35倍多点。那么我们理论上调用36次就可以把全部结果拿到了。那么为了防止漏拿和尽量不重复拿,我们该如何去做呢?
- 把北京市切割成36份。比如切割成矩形。那么每一份知道其左下角和右上角坐标,我们就可以唯一确定一个矩形。
- 根据规则 bounds 就可以搜索了 例如
那么还有一个问题,北京市的边界坐标是什么。这个问题我有个思路,
从百度百科上查询到北京的面积大小为 1.641万平方千米
根据面积公式 S= ab (长乘以宽) 假设北京市一个正方形,那么可以计算得出
s = a*a
a =128KM
那么距离中心点左右长度为64KM
但是这样有个前提是假设北京市个正方形。 那么实际以天安门为中心点(GPS坐标116.395645038,39.9299857781 )的矩形是什么样子的呢?如下图
这里就有个问题,我不仅没有把北京全包进去,而且会多出廊坊的区域,这样我切割完小矩形,其实有很多是无效的
所以我想到了外一种近似方式,一般城市大小也就中心点坐标上下左右30KM吧
所以北京如下
不在这个区域的很少。
当然这个30是经过一定考量的,目前只对北京市有效,比如成都啊,海南啊,还是不行。中国一共有355个城市,每一个我觉得得人工去丈量一下。
接下来我们切割矩形,计算每个矩形的左下角和右上角的坐标点,这样就可以搜索了
百度地图的源码是
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<style type="text/css">
body, html {width: 100%;height: 100%;margin:0;font-family:"微软雅黑";}
#allmap{width:100%;height:500px;}
p{margin-left:5px; font-size:14px;}
</style>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=您的密钥"></script>
<title>搜索区域内关键词</title>
</head>
<body>
<div id="allmap"></div>
<p>返回北京市矩形框区域范围内的“银行”关键字的检索结果,并展示在地图上</p>
</body>
</html>
<script type="text/javascript">
// 百度地图API功能
var map = new BMap.Map("allmap"); // 创建Map实例
map.centerAndZoom(new BMap.Point(116.274625,39.961627), 11);
map.enableScrollWheelZoom(); //启用滚轮放大缩小
var local = new BMap.LocalSearch(map, {
renderOptions:{map: map}
});
var pStart = new BMap.Point(116.274625,39.961627);
var pEnd = new BMap.Point(116.367474,39.988609);
var bs = new BMap.Bounds(pStart,pEnd); //自己规定范围
local.searchInBounds("银行", bs);
var polygon = new BMap.Polygon([
new BMap.Point(pStart.lng,pStart.lat),
new BMap.Point(pEnd.lng,pStart.lat),
new BMap.Point(pEnd.lng,pEnd.lat),
new BMap.Point(pStart.lng,pEnd.lat)
], {strokeColor:"blue", strokeWeight:6, strokeOpacity:0.5});
map.addOverlay(polygon);
</script>
结果为
另外一个关键的切割矩形的算法,python实现。
源码是