之前找数据时,我遇到过这样一个问题:我需要确定东莞市33个镇和街道的经纬度,以及任意两个镇或街道之间行车距离。用过地图软体的童鞋都知道地图软体里一定都存著这些数据,但是需要自己一个一个搜,而且有些数据在app里是看不到的,比如经纬度。好在我知道大部分提供信息的网站都有开放平台,是给开发者接入到软体里的,得用程序语言才能获取其中的数据,正好我会python,那就开始吧~

国内两大地图平台百度和高德都有各自的开放平台,这里就用高德做示范。高德开放平台的主页:高德开放平台 | 高德地图API,进去以后,是这样的:

第一次用需要注册,点击右上角的注册:

这就是注册页面,注册成功后,你就成为了一名高德开发者,我就不示范了。有了账号之后还是回到主页,点击右上角的登录,登录之后,右上角会变成这样:

进入控制台,是这个样子的:

如果是第一次用,先点左侧的引用管理,创建应用和秘钥,这里我演示一下:

点击右上角的创建新应用,给应用起一个名字,根据需要选一个应用类型,创建好了之后这个应用就会出现在页面中,再点击该应用右上角的添加新key,创建一个秘钥:

给key起一个名字,服务平台选web服务(毕竟我们不是在手机上用),下面提示你可使用的服务,这些你都可以用,IP白名单中你可以添加自己的IP地址,不填也可以。最后勾选同意,提交。

然后你就拥有了一个属于你的key。每一个key都有每天调用次数的限制,为了防止被别人使用,注意保护好隐私。

现在就可以用这个key获取高德地图的数据了。在个人中心→配额管理中,我们可以看到每一项服务的每日调用量上限,如果是免费用户,配额就是这样的:

点击页面右上角的开发者文档,可以查看每一项服务的详细说明。我们添加key时选的是web服务,那就翻到这里:

比如我现在要通过街道和镇的名字获取它们的经纬度,那就选择搜索API。

看一下文档的内容:

产品介绍:搜索服务API是一类简单的HTTP介面,提供多种查询POI信息的能力,其中包括关键字搜索、周边搜索、多边形搜索、ID查询四种筛选机制。

我们要用的关键字搜索:

关键字搜索:通过用POI的关键字进行条件搜索,例如:肯德基、朝阳公园等;同时支持设置POI类型搜索,例如:银行

使用说明:

第一步,申请」Web服务API」密钥(Key);

第二步,拼接HTTP请求URL,第一步申请的Key需作为必填参数一同发送;第三步,接收HTTP请求返回的数据(JSON或XML格式),解析数据。

秘钥已经有了,下面需要拼接请求:

关键字搜索API服务地址:https://restapi.amap.com/v3/place/text?parameters

parameters就是我们需要修改的部分,根据文档中的请求参数的说明,我们需要拼接到路径中的参数有:

key:自己的秘钥

keywords:关键字,在这里是东莞市各镇街的名称

city:查询城市范围,即东莞,或查询高德的编码表,用东莞的adcode代替汉字

offset和page:每页数据条数和当前页数,我们只需要第一页的第一条,都是1,一般会返回各镇街行政中心的数据

output:返回数据的类型,我一般用JSON,也可用XML

最后拼接出来的请求就是:

http://restapi.amap.com/v3/place/text?keywords=i&city=东莞&output=json&offset=1&page=1&key=mykey1

其中的keywords=i,可以将i替换成镇街的名称,mykey1换成自己的秘钥。

这个请求用浏览器也能读取,那我们就先看一看高德返回给我们的数据是什么样的。记住这个结构,后面要用关键字和索引读取location后面的经纬度,路径是:pois→0→location

下面就该请python登场了,需要用到的几个库:

import urllib.request #发送请求
from urllib import parse #URL编码
import json #解析json数据
from openpyxl import load_workbook #从Excel中读取镇街名称

我的数据保存在xlsx文件里,

所以要用openpyxl读取各镇街的名称:

nameList = [] #创建一个列表用于接收数据
book = load_workbook(dongguan.xlsx) #打开文件
nameSheet = book["data"] #读取工作表
#按行读取第一列,并存入列表:
for row in range(1,nameSheet.max_row+1):
nameList.append(str(nameSheet["A%d"%(row)].value))

下面就该发送请求了:

dict = {} #创建一个字典用于接收数据
for i in nameList:
#拼接请求
url1 = http://restapi.amap.com/v3/place/text?keywords=+i+&city=东莞&output=json&offset=1&page=1&key=mykey1
#将一些符号进行URL编码
newUrl1 = parse.quote(url1, safe="/:=&?#+!$,;@()*[]")
#发送请求
response1 = urllib.request.urlopen(newUrl1)
#读取数据
data1 = response1.read()
#解析json数据
jsonData1 = json.loads(data1)
#pois→0→location得到经纬度,写入字典
dict[i] = jsonData1[pois][0][location]
#拆分字元串,逗号之前是经度,逗号之后是纬度
locations = dict[i].split(",")

最后得到的数据,也可以写入Excel文件里。

下一步,就该获取距离数据了,这一部分用的是路径规划API,还是先看一下开发者文档:

产品介绍:

路径规划API是一套以HTTP形式提供的步行、公交、驾车查询及行驶距离计算介面,返回JSON 或 XML格式的查询数据,用于实现路径规划功能的开发。使用说明:第一步,申请」Web服务API」密钥(Key);第二步,拼接HTTP请求URL,第一步申请的Key需作为必填参数一同发送;第三步,接收HTTP请求返回的数据(JSON或XML格式),解析数据。

我要用的是驾车路径规划,示例:

https://restapi.amap.com/v3/direction/driving?origin=116.481028,39.989643&destination=116.465302,40.004717&extensions=all&output=xml&key=<用户的key>

我需要提交的请求:

key:秘钥

origin:起点的经纬度

destination:终点的经纬度

strategy:行驶策略,我选择距离最短,代码是2

output:返回数据类型,默认json

最后我拼接出来的请求就是:

https://restapi.amap.com/v3/driving?origin=origin&destination=destination&extensions=all&strategy=2&output=json&key=mykey1

origin和destination换成上面得到的经纬度,就可以了。我们也可以用浏览器先看看数据是什么样的。返回了许多数据,如果只要第三行的distance,路径为:route→paths→0→distance

好了,发送请求:

distanceList = [] #创建一个列表用于接收数据
k = len(nameList) #nameList列表中元素个数
#遍历nameList列表
for m in range(k):
subList = [] #创建一个子列表用于接收每一条数据,主要是为了后面方便创建数组
for n in range(k):
#从nameList中得到镇街的名称,作为键,获得dict中的经纬度
origin = dict[nameList[m]]
destination = dict[nameList[n]]
#拼接请求
url2 = https://restapi.amap.com/v3/driving?origin=+origin+&destination=+destination+&extensions=all&type=1&output=json&key=mykey1
#编码
newUrl2 = parse.quote(url2, safe="/:=&?#+!$,;@()*[]")
#发送请求
response2 = urllib.request.urlopen(newUrl2)
#接收数据
data2 = response2.read()
#解析json文件
jsonData2 = json.loads(data2)
#从json文件中提取距离
distance = jsonData2[route][path][0][distance]
#将距离写入子列表
subList.append(int(distance))
#看一下得到的数据,这一行有没有无所谓
print(nameList[m],nameList[n],distance)
#将子列表写入distanceList
distanceList.append(subList)

这个得到的数据也可以写进excel文件,就像这样:

好了,批量获取数据的任务到这里就完成了。

需要注意的是,驾车路径规划API每天的配额是2000,我这里有33个镇和街道,穷举两两组合,就要调用33*(33-1)/2 = 528次,如果有64个,就要调用2016次,2000的配额就不够用了。

其实调用API和爬虫技术的原理是差不多的,都是向对方的伺服器发送一个请求,对方返回一些数据,但调用API比爬虫简单很多,因为没有反爬限制,返回的数据也是对方已经整理好的。只要有一点Python基础,能看得懂我写的代码,就可以获取海量的地理数据。

最后要说的是,在返回的json里还有很多数据,高德开放平台提供的API也有很多功能,怎么用,都在开发文档里,另外百度地图开放平台也可以批量获取数据,也有一些区别于高德的功能,有需要就自己探索吧。

推荐阅读:

查看原文 >>
相关文章