科研需要POI哪里找,不妨动手自己跑。
接口描述
本文基于高德开放服务之web API提供的搜索POI接口爬取数据。
接口描述见:https://lbs.amap.com/api/webservice/guide/api/search
使用API前您需先申请Key,若无高德地图API账号需要先申请账号。
要爬取研究区域范围内的所需类型的所有POI数据,应该采用那种接口呢?
多边形搜索
多边形搜索API服务地址:https://restapi.amap.com/v3/place/polygon?parameters
parameters代表的参数包括必填参数和可选参数。所有参数均使用和号字符(&)进行分隔。下面的列表枚举了其中一些参数及其使用规则:
polygon:
必填
规则:经度和纬度用",“分割,经度在前,纬度在后,坐标对用”|"分割。经纬度小数点后不得超过6位。
多边形为矩形时,可传入左上右下两顶点坐标对;其他情况下首尾坐标对需相同。
type:
可选
分类代码由六位数字组成,一共分为三个部分,前两个数字代表大类;中间两个数字代表中类;最后两个数字代表小类。
若指定了某个大类,则所属的中类、小类都会被显示。
当指定010000,则010100等中类、010101等小类都会被包含。
当指定010900,则010901等小类都会被包含
分类代码下载地址:https://lbs.amap.com/api/webservice/download
注:当keywords和types为空的时候, 我们会默认指定types为120000(商务住宅)&150000(交通设施服务)
offset
可选
每页记录数据
强烈建议不超过25,若超过25可能造成访问报错
默认20
page
可选
当前页数
最大翻页数100
爬取数量限制
由上面的参数规则,我们不难发现,爬取一个区域的POI如果数量较多,比方说上万,那么直接调用API返回的结果,最多只能返回:
offset * page = 25 * 100 = 2500
nonono
官方有提示:
另外,无论指定多少个type,每次请求最多返回1000个POI信息,若场景需要获取更可能多的POI;建议您不要在type之中指定过多的类别,而是分多次请求从而得到更加准确的结果。
所以单词调用api1000之后的点数据就无法获取了。
同时官方有流量限制:
也就是说,一个账户,单日在不断调用api的情况下,可以获取的数据量为:
1000 * 2000 = 200 0000
嗯,这样看数据量还比较可观。
那么就需要我们解决分割我们的矩形区域,使得单次返回的数据量在限定值以下,如果数量超出,我们就继续把这个矩形区域进行分割。
咦,这不就是四叉树索引嘛
建立四叉树索引
首先 我们需要设置我们数据限额,一个小于1000的数,我们设置为800吧。
static final int NUM = 800;//可以范围的最大数目,如果大于800,多出的数目不会返回
然后 我们定义一个我们的索引范围:研究范围
可以根据左上和右下两个点确定矩形范围
//通过左上角和右下角两点确定矩形范围,进行多边形搜索
//输入坐标范围为WGS-84坐标系
static double lux = 120.852722;//左上X
static double luy = 31.874695;//左上Y
static double rdx = 122.242493;//右下X
static double rdy = 30.677917;//右下Y
接下来 我们设置我们的KEY、要获取的POI类型码、保存的txt的路径
static String[] type = {
"090100","090101",
"090102","0902","0903","0904",
"0905","0906","0907"};//type和keyword必须二选一输入参数,这里选择type
static String citycode = "021";//城市编码
static String path = "C:/个人/data/poi/";
static int offset = 20;//每页显示的POI数目,限制小于25
在接口之中,可以通过city&citylimit参数指定希望搜索的城市或区县。而city参数能够接收citycode和adcode,citycode仅能精确到城市,而adcode却能够精确到区县。这里选择citycode,如果研究范围是一个市的话。
/**
* 创建空间索引四叉树
* @param root 输入根节点,根节点覆盖研究范围
*/
public static void create(Node root, String type,BufferedWriter bw) {
String param = root._lux+","+root._luy+";"+root._rdx+","+root._rdy+";";
int page = 1;
String result = requestGet(type, param, page).toString();
Gson gson = new Gson();
Count c = gson.fromJson(result, Count.class);
if(c.status == 0) {
System.out.println("request failed");
}else if (c.count<NUM) {
//读取每页记录
System.out.println(c.count);
try {
while (true) {
String re = requestGet(type, param, page).toString();
Info info = gson.fromJson(re, Info.class);
if(info.count == 0) {
break;
}
for(Poi poi: info.pois