文档章节

爬取高德地图poi数据

chro008
 chro008
发布于 2018/09/18 14:27
字数 4020
阅读 2.2W
收藏 23
POI

阿里云携手百名商业领袖、技术大咖,带您一探行进中的数字新基建!>>>

高德地图搜索poi的api介绍地址

当前想法是爬取目标区域(作者所在小县城)的所有poi数据,存到数据库中作为原始数据,然后供其它系统调用,因为之前爬取过百度地图的poi数据,所以这次工作就驾轻就熟了。

1、首先注册一个高德地图的开发者账号,申请一个绑定Web服务的key,然后把刚注册的开发者账号认证一下: 申请账号、key就不赘述了,去高德地图开发平台很简单就能完成了,将账号认证是为了提高每日访问高德地图api接口的次数限制和并发请求。

2、根据上方api地址里面的介绍,总共分为4中搜索: 关键字搜索:通过用POI的关键字进行条件搜索,例如:肯德基、朝阳公园等;同时支持设置POI类型搜索,例如:银行 周边搜索:在用户传入经纬度坐标点附近,在设定的范围内,按照关键字或POI类型搜索; 多边形搜索:在多边形区域内进行搜索 ID查询:通过POI ID,查询某个POI详情,建议可同输入提示API配合使用

我的目标是某个区域的所有poi,所以选择的第三种:多边形搜索

3、多边形搜索最重要的参数就是polygon-》经纬度坐标对,我在百度地图坐标拾取系统拾取了我的目标区域的经纬度坐标对,如下图: 百度地图坐标拾取系统

3步准备工作到这里就差不多结束了,在正式开始码代码之前先做个测试吧,用浏览器直接访问接口看看返回的数据(当然,高德的api接口有返回数据说明)

api返回数据1

如上图,这里比较重要的一个属性是count,根据api的介绍count是搜索方案数目(最大值为1000),所以说每次请求都会返回当前所搜所包含的poi个数,而大于1000的poi是没有办法获取到的。那么我如果想查询某个区域的全部数据,可以将这个区域再划分成更小的区域(显然是个递归操作)的集合,然后把这几个可以查到所有poi的区域的所有poi数据结合起来就是我最终需要的数据。可能口述不明朗,可以见下方草图:

划分区域草图

好,可以开始撸代码了:

因为,整个调用API的过程都离不开经纬度,所以首先定义一个经纬度描述的类 `

//矩形块的经纬度标识, 左上角的经纬度 和右下角的经纬度
class RectangleCoordinate {

    /**
     * 矩形左上角经度
     */
    private double x0;

    /**
     * 矩形左上角纬度
     */
    private double y0;

    /**
     * 矩形右下角经度
     */
    private double x1;

    /**
     * 矩形右下角纬度
     */
    private double y1;


    public RectangleCoordinate(double x0, double y0, double x1, double y1) {
        this.x0 = x0;
        this.y0 = y0;
        this.x1 = x1;
        this.y1 = y1;
    }

    /**
     * [@return](https://my.oschina.net/u/556800) 获取矩形中心线的纬度
     */
    public double getAverageY() {
        return (y0 + y1) / 2;
    }

    /**
     * [@return](https://my.oschina.net/u/556800) 获取矩形中心线的经度
     */
    public double getAverageX() {
        return (x0 + x1) / 2;
    }

    public double getX0() {
        return x0;
    }

    public void setX0(double x0) {
        this.x0 = x0;
    }

    public double getY0() {
        return y0;
    }

    public void setY0(double y0) {
        this.y0 = y0;
    }

    public double getX1() {
        return x1;
    }

    public void setX1(double x1) {
        this.x1 = x1;
    }

    public double getY1() {
        return y1;
    }

    public void setY1(double y1) {
        this.y1 = y1;
    }

    [@Override](https://my.oschina.net/u/1162528)
    public String toString() {
        return x0 + "," + y0 + "|" + x1 + "," + y1;
    }
}`

然后需要一个调用api,获取返回数据的方法,这个方法参数就是矩形块,当然还需要一个页数,即当前方法获取的是某个矩形区域的第X页的数据(每页上线25个poi,默认20个poi)

/**
     * @return 获取矩形块的poi数据
     */
    private JSONObject getSearchResult(RectangleCoordinate coordinate, int page) {
        RestTemplate restTemplate = new RestTemplate();
        String url = getRequestGaodeUrl(coordinate,page);
        String result = restTemplate.getForObject(url, String.class);
        try {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return JSONObject.parseObject(result);
        } catch (Exception e) {
            logger.error("an error occurred when getting response of gaode map data for coordinate:[{}]", coordinate.toString());
        }
        return null;
    }

当然,上方已经说过,如果矩形块返回数据count=1000,就说明当前矩形块需要分割,我的想法比较简单,将矩形块按照上方草图,在水平中心和垂直分心分割,1个矩形块就分割成4个小矩形块了,方法如下:

 /**
     * @return 将矩形4等分成小矩形 然后返回4个 小矩形的经纬度集合
     */
    private List<RectangleCoordinate> getSplitRectangleList(RectangleCoordinate coordinate) {
        List<RectangleCoordinate> splitRectangleList = new LinkedList<>();
        splitRectangleList.add(new RectangleCoordinate(coordinate.getX0(), coordinate.getY0(), coordinate.getAverageX(), coordinate.getAverageY()));
        splitRectangleList.add(new RectangleCoordinate(coordinate.getAverageX(), coordinate.getY0(), coordinate.getX1(), coordinate.getAverageY()));
        splitRectangleList.add(new RectangleCoordinate(coordinate.getX0(), coordinate.getAverageY(), coordinate.getAverageX(), coordinate.getY1()));
        splitRectangleList.add(new RectangleCoordinate(coordinate.getAverageX(), coordinate.getAverageY(), coordinate.getX1(), coordinate.getY1()));
        return splitRectangleList;
    }

目前,可以获取到矩形区域经纬度对的集合了,也有获取api数据的方法了,然后就是遍历页数获取数据,自定义操作数据。 当某次分页请求返回的poi个数小于每页最大个数的时候就认为当前区域poi已经完全请求到了。

 private void startAnaMainGaode(RectangleCoordinate coordinate) throws AnalysisException {
        //当前爬取的数据的页数索引
        int page_num = 0;
        //当前爬取内容是否是最后一页
        boolean isLastPage = false;
        JSONObject searchResult;
        JSONArray datas = null;
        logger.info("ready to analysis coordinate:[{}]", coordinate.toString());
        while (!isLastPage) {
            logger.info("is going to get data for page_" + page_num);
            try {
                searchResult = getSearchResult(coordinate, page_num);
                datas = searchResult.getJSONArray("pois");
            } catch (Exception e) {
                logger.error("an error occurred when getting response of gaode map data for coordinate:[{}]", coordinate.toString());
            }
            if (datas != null && datas.size() < 20) {
                isLastPage = true;
                logger.info("get result counts is [{}], now page index is [{}]", datas.size(), page_num);
            }
            saveIntoDbGaode(datas);
            page_num++;
        }
    }

private void saveIntoDbGaode(JSONArray result) {
    JSONObject resultItem;

    for (int i = 0; i < result.size(); i++) {
        resultItem = result.getJSONObject(i);
        try {
            results.add(getInsertUnitObject(resultItem));
        } catch (Exception e) {
            logger.error("生成数据时异常,e: {}", e.getMessage());
            e.printStackTrace();
        }
    }
    if (results.size() > BATCHINSERTLIMIT || ISLAST) {
        logger.info("is ready to batch insert into unit, total count is {}", results.size());
        try {
            dao.batchAddUnitGaode(results);
        } catch (Exception e) {
            logger.error("更新数据库异常,e: {}", e.getMessage());
        }
        results = new JSONArray();
    }
}`

到此,基本方法都介绍过了,全部代码如下(因为都是简单方法和逻辑,不明白的留言交流)

//请求入口 
public void GaodePoiSearch() { 
    //徐水区 final RectangleCoordinate searchAreaCoordinate = new RectangleCoordinate(115.521773, 39.106335, 115.801182, 38.943988);    
    //保定市
    //final RectangleCoordinate searchAreaCoordinate = new RectangleCoordinate(114.332719,39.574064, 116.588688,38.179144);

    List<RectangleCoordinate> validCoordinate = getValidCoordinate(searchAreaCoordinate);
    logger.info("get all valid coordinate,size is [{}]", validCoordinate.size());
    /**
     * 获取到所有的小方块之后可以做一些处理, 比如存储到某个地方,以防发生异常,方便后面重新遍历,我这里暂未做处理
     */
    validCoordinate.forEach(coor -> {
        try {
            startAnaMainGaode(coor);
        } catch (AnalysisException e) {
            e.printStackTrace();
        }
    });

    ISLAST = true;
    saveIntoDbGaode(new JSONArray());
}

/**
 * [@return](https://my.oschina.net/u/556800) 获取矩形块中 符合 调用api的 小矩形块的集合
 * 因为高德地图某个矩形块只能获取前1000条,所以要将矩形块分割成可以获取到全部数据的矩形块
 * 如果当前矩形块请求数据返回的count<1000 即为符合条件的,否则将矩形块4等分 然后递归
 */
private List<RectangleCoordinate> getValidCoordinate(RectangleCoordinate coordinate) {
    List<RectangleCoordinate> validCoordinate = new LinkedList<>();
    JSONObject searchResult = getSearchResult(coordinate, 0);
    if (searchResult.getIntValue("count") >= 1000) {
        List<RectangleCoordinate> splitRectangleList = getSplitRectangleList(coordinate);
        splitRectangleList.forEach(coor -> validCoordinate.addAll(getValidCoordinate(coor)));
    } else {
        logger.info("add a valid coordinate [{}]", coordinate.toString());
        validCoordinate.add(coordinate);
    }
    return validCoordinate;
}

/**
 * [@return](https://my.oschina.net/u/556800) 将矩形4等分成小矩形 然后返回4个 小矩形的经纬度集合
 */
private List<RectangleCoordinate> getSplitRectangleList(RectangleCoordinate coordinate) {
    List<RectangleCoordinate> splitRectangleList = new LinkedList<>();
    splitRectangleList.add(new RectangleCoordinate(coordinate.getX0(), coordinate.getY0(), coordinate.getAverageX(), coordinate.getAverageY()));
    splitRectangleList.add(new RectangleCoordinate(coordinate.getAverageX(), coordinate.getY0(), coordinate.getX1(), coordinate.getAverageY()));
    splitRectangleList.add(new RectangleCoordinate(coordinate.getX0(), coordinate.getAverageY(), coordinate.getAverageX(), coordinate.getY1()));
    splitRectangleList.add(new RectangleCoordinate(coordinate.getAverageX(), coordinate.getAverageY(), coordinate.getX1(), coordinate.getY1()));
    return splitRectangleList;
}

/**
 * @return 获取矩形块的poi数据
 */
private JSONObject getSearchResult(RectangleCoordinate coordinate, int page) {
    RestTemplate restTemplate = new RestTemplate();
    String url = getRequestGaodeUrl(coordinate,page);
    String result = restTemplate.getForObject(url, String.class);
    try {
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return JSONObject.parseObject(result);
    } catch (Exception e) {
        logger.error("an error occurred when getting response of gaode map data for coordinate:[{}]", coordinate.toString());
    }
    return null;
}

private void startAnaMainGaode(RectangleCoordinate coordinate) throws AnalysisException {
    //当前爬取的数据的页数索引
    int page_num = 0;
    //当前爬取内容是否是最后一页
    boolean isLastPage = false;
    JSONObject searchResult;
    JSONArray datas = null;
    logger.info("ready to analysis coordinate:[{}]", coordinate.toString());
    while (!isLastPage) {
        logger.info("is going to get data for page_" + page_num);
        try {
            searchResult = getSearchResult(coordinate, page_num);
            datas = searchResult.getJSONArray("pois");
        } catch (Exception e) {
            logger.error("an error occurred when getting response of gaode map data for coordinate:[{}]", coordinate.toString());
        }
        if (datas != null && datas.size() < 20) {
            isLastPage = true;
            logger.info("get result counts is [{}], now page index is [{}]", datas.size(), page_num);
        }
        saveIntoDbGaode(datas);
        page_num++;
    }
}

private void saveIntoDbGaode(JSONArray result) {
    JSONObject resultItem;

    for (int i = 0; i < result.size(); i++) {
        resultItem = result.getJSONObject(i);
        try {
            results.add(getInsertUnitObject(resultItem));
        } catch (Exception e) {
            logger.error("生成数据时异常,e: {}", e.getMessage());
            e.printStackTrace();
        }
    }
    if (results.size() > BATCHINSERTLIMIT || ISLAST) {
        logger.info("is ready to batch insert into unit, total count is {}", results.size());
        try {
            dao.batchAddUnitGaode(results);
        } catch (Exception e) {
            logger.error("更新数据库异常,e: {}", e.getMessage());
        }
        results = new JSONArray();
    }
}

private JSONObject getInsertUnitObject(JSONObject resultItem) {
    JSONObject unitDataObject = new JSONObject();
    unitDataObject.put("uid", resultItem.getString("id"));
    unitDataObject.put("name", resultItem.getString("name"));
    unitDataObject.put("type", resultItem.getString("type"));
    unitDataObject.put("tag", resultItem.getString("type"));
    unitDataObject.put("address", resultItem.getString("address"));
    unitDataObject.put("province", resultItem.getString("pname"));
    unitDataObject.put("city", resultItem.getString("cityname"));
    unitDataObject.put("area", resultItem.getString("adname"));

    String tel = resultItem.getString("tel");
    if (tel != null && !"[]".equals(tel)) {
        unitDataObject.put("telephone", tel);
    }

    try {
        JSONArray url = resultItem.getJSONArray("website");
        if (url != null && url.size() > 0) {
            unitDataObject.put("detail_url", url.getString(0));
        }
    } catch (Exception e) {
        unitDataObject.put("detail_url", resultItem.getString("website"));
    }

    JSONArray photos = resultItem.getJSONArray("photos");
    if (photos != null && photos.size() > 0) {
        StringBuilder images = new StringBuilder();
        for (int j = 0; j < photos.size(); j++) {
            images.append(j == 0 ? "" : ";").append(photos.getJSONObject(j).getString("url"));
        }
        unitDataObject.put("images", images.toString());
    }

    String entr_location = resultItem.getString("location");
    if (StringUtils.isEmpty(entr_location)) {
        entr_location = resultItem.getString("entr_location");
    }

    if (!StringUtils.isEmpty(entr_location)) {
        unitDataObject.put("lng", entr_location.split(",")[0]);
        unitDataObject.put("lat", entr_location.split(",")[1]);
    }
    return unitDataObject;
}

private String getRequestGaodeUrl(RectangleCoordinate coordinate, int page) {
    return "https://restapi.amap.com/v3/place/polygon?" +
            "key=xxxxxxxxxxxxxxxxxxxxxxx&polygon=" + coordinate.toString() + "&page=" + page + "&types=010000|" +
            "010100|010101|010102|010103|010104|010105|010107|010108|010109|010110|010111|010112|010200|010300|010400|" +
            "010401|010500|010600|010700|010800|010900|010901|011000|011100|020000|020100|020101|020102|020103|020104|" +
            "020105|020106|020200|020201|020202|020203|020300|020301|020400|020401|020402|020403|020404|020405|020406|" +
            "020407|020408|020600|020601|020602|020700|020701|020702|020703|020800|020900|020904|020905|021000|021001|" +
            "021002|021003|021004|021100|021200|021201|021202|021203|021300|021301|021400|021401|021500|021501|021600|" +
            "021601|021602|021700|021701|021702|021800|021802|021803|021804|021900|022000|022100|022200|022300|022301|" +
            "022400|022500|022501|022502|022600|022700|022800|022900|023000|023100|023200|023300|023301|023400|023500|" +
            "025000|025100|025200|025300|025400|025500|025600|025700|025800|025900|026000|026100|026200|026300|029900|" +
            "030000|030100|030200|030201|030202|030203|030204|030205|030206|030300|030301|030302|030303|030400|030401|" +
            "030500|030501|030502|030503|030504|030505|030506|030507|030508|030700|030701|030702|030800|030801|030802|" +
            "030803|030900|031000|031004|031005|031100|031101|031102|031103|031104|031200|031300|031301|031302|031303|" +
            "031400|031401|031500|031501|031600|031601|031700|031701|031702|031800|031801|031802|031900|031902|031903|" +
            "031904|032000|032100|032200|032300|032400|032401|032500|032600|032601|032602|032700|032800|032900|033000|" +
            "033100|033200|033300|033400|033401|033500|033600|035000|035100|035200|035300|035400|035500|035600|035700|" +
            "035800|035900|036000|036100|036200|036300|039900|040000|040100|040101|040200|040201|050000|050100|050101|" +
            "050102|050103|050104|050105|050106|050107|050108|050109|050110|050111|050112|050113|050114|050115|050116|" +
            "050117|050118|050119|050120|050121|050122|050123|050200|050201|050202|050203|050204|050205|050206|050207|" +
            "050208|050209|050210|050211|050212|050213|050214|050215|050216|050217|050300|050301|050302|050303|050304|" +
            "050305|050306|050307|050308|050309|050310|050311|050400|050500|050501|050502|050503|050504|050600|050700|" +
            "050800|050900|060000|060100|060101|060102|060103|060200|060201|060202|060300|060301|060302|060303|060304|" +
            "060305|060306|060307|060308|060400|060401|060402|060403|060404|060405|060406|060407|060408|060409|060411|" +
            "060413|060414|060415|060500|060501|060502|060600|060601|060602|060603|060604|060605|060606|060700|060701|" +
            "060702|060703|060704|060705|060706|060800|060900|060901|060902|060903|060904|060905|060906|060907|061000|" +
            "061001|061100|061101|061102|061103|061104|061200|061201|061202|061203|061204|061205|061206|061207|061208|" +
            "061209|061210|061211|061212|061213|061214|061300|061301|061302|061400|061401|070000|070100|070200|070201|" +
            "070202|070203|070300|070301|070302|070303|070304|070305|070306|070400|070401|070500|070501|070600|070601|" +
            "070603|070604|070605|070606|070607|070608|070609|070610|070700|070701|070702|070703|070704|070705|070706|" +
            "070800|070900|071000|071100|071200|071300|071400|071500|071600|071700|071800|071801|071900|071901|071902|" +
            "071903|072000|072001|080000|080100|080101|080102|080103|080104|080105|080106|080107|080108|080109|080110|" +
            "080111|080112|080113|080114|080115|080116|080117|080118|080119|080200|080201|080202|080300|080301|080302|" +
            "080303|080304|080305|080306|080307|080308|080400|080401|080402|080500|080501|080502|080503|080504|080505|" +
            "080600|080601|080602|080603|090000|090100|090101|090102|090200|090201|090202|090203|090204|090205|090206|" +
            "090207|090208|090209|090210|090211|090300|090400|090500|090600|090601|090602|090700|090701|090702|100000|" +
            "100100|100101|100102|100103|100104|100105|100200|100201|110000|110100|110101|110102|110103|110104|110105|" +
            "110106|110200|110201|110202|110203|110204|110205|110206|110207|110208|110209|120000|120100|120200|120201|" +
            "120202|120203|120300|120301|120302|120303|120304|130000|130100|130101|130102|130103|130104|130105|130106|" +
            "130107|130200|130201|130202|130300|130400|130401|130402|130403|130404|130405|130406|130407|130408|130409|" +
            "130500|130501|130502|130503|130504|130505|130506|130600|130601|130602|130603|130604|130605|130606|130700|" +
            "130701|130702|130703|140000|140100|140101|140102|140200|140201|140300|140400|140500|140600|140700|140800|" +
            "140900|141000|141100|141101|141102|141103|141104|141105|141200|141201|141202|141203|141204|141205|141206|" +
            "141207|141300|141400|141500|150000|150100|150101|150102|150104|150105|150106|150107|150200|150201|150202|" +
            "150203|150204|150205|150206|150207|150208|150209|150210|150300|150301|150302|150303|150304|150400|150500|" +
            "150501|150600|150700|150701|150702|150703|150800|150900|150903|150904|150905|150906|150907|150908|150909|" +
            "151000|151100|151200|151300|160000|160100|160101|160102|160103|160104|160105|160106|160107|160108|160109|" +
            "160110|160111|160112|160113|160114|160115|160117|160118|160119|160120|160121|160122|160123|160124|160125|" +
            "160126|160127|160128|160129|160130|160131|160132|160133|160134|160135|160136|160137|160138|160139|160140|" +
            "160141|160142|160143|160144|160145|160146|160147|160148|160149|160150|160151|160152|160200|160300|160301|" +
            "160302|160303|160304|160305|160306|160307|160308|160309|160310|160311|160312|160314|160315|160316|160317|" +
            "160318|160319|160320|160321|160322|160323|160324|160325|160326|160327|160328|160329|160330|160331|160332|" +
            "160333|160334|160335|160336|160337|160338|160339|160340|160341|160342|160343|160344|160345|160346|160347|" +
            "160348|160349|160400|160401|160402|160403|160404|160405|160406|160407|160408|160500|160501|160600|170000|" +
            "170100|170200|170201|170202|170203|170204|170205|170206|170207|170208|170209|170300|170400|170401|170402|" +
            "170403|170404|170405|170406|170407|170408|180000|180100|180101|180102|180103|180104|180200|180201|180202|" +
            "180203|180300|180301|180302|180400|180500|190000|190100|190101|190102|190103|190104|190105|190106|190107|" +
            "190108|190109|190200|190201|190202|190203|190204|190205|190300|190301|190302|190303|190304|190305|190306|" +
            "190307|190308|190309|190310|190311|190400|190401|190402|190403|190500|190600|190700|200000|200100|200200|" +
            "200300|200301|200302|200303|200304|200400|220000|220100|220101|220102|220103|220104|220105|220106|220107|" +
            "220200|220201|220202|220203|220204|220205|970000|990000|991000|991001|991400|991401|991500&extensions=all";
}

/**
 * 矩形块的经纬度标识, 左上角的经纬度 和右下角的经纬度
 */
class RectangleCoordinate {

    /**
     * 矩形左上角经度
     */
    private double x0;

    /**
     * 矩形左上角纬度
     */
    private double y0;

    /**
     * 矩形右下角经度
     */
    private double x1;

    /**
     * 矩形右下角纬度
     */
    private double y1;


    public RectangleCoordinate(double x0, double y0, double x1, double y1) {
        this.x0 = x0;
        this.y0 = y0;
        this.x1 = x1;
        this.y1 = y1;
    }

    /**
     * @return 获取矩形中心线的纬度
     */
    public double getAverageY() {
        return (y0 + y1) / 2;
    }

    /**
     * @return 获取矩形中心线的经度
     */
    public double getAverageX() {
        return (x0 + x1) / 2;
    }

    public double getX0() {
        return x0;
    }

    public void setX0(double x0) {
        this.x0 = x0;
    }

    public double getY0() {
        return y0;
    }

    public void setY0(double y0) {
        this.y0 = y0;
    }

    public double getX1() {
        return x1;
    }

    public void setX1(double x1) {
        this.x1 = x1;
    }

    public double getY1() {
        return y1;
    }

    public void setY1(double y1) {
        this.y1 = y1;
    }

    @Override
    public String toString() {
        return x0 + "," + y0 + "|" + x1 + "," + y1;
    }
}`

更新(2018-09-20):

1、时间问题,当前50ms请求一次api接口,跑完小县城的数据(几万条)大概需要十分钟左右吧,把整个市区主要数据跑完断断续续的用了一天吧,最后跑了近27W数据

2、应用问题,原本的想法就是做个简单的小程序,把跑来的数据加以利用,做个电话本类似的应用,具体可以扫下方小程序码体验

更新(2019-01-28):

有一些朋友向我要源码,可能大多是新手,尽管思路给了,代码还是写不出来。其实上方我把主要的代码基本都发布出来了,但是应各位要求,我把源码提交到github了,可以访问 我的github 查看

更新(2019-07-24)

想到一个弊端,并找到了解决方法:

很多朋友使用上文提供的方法时,难免会得到一些”垃圾数据“,何为垃圾数据呢?比如我爬取保定的某些数据,开始大致选了一个区域,为了爬取到所有的数据,就要保证所选区域要涵盖保定,最后爬到的数据就不止保定的数据了,其他区域的数据就为垃圾数据,如下图:

看到没有,在尽可能小的区域内,垃圾数据所在区域也几乎占了小一半了,除了临近的市区(任丘等),也包含了其他省(山西,北京等)的数据。除了区域不精准,更可怕的是像北京这种大城市,poi数量很大,所以会造成爬取的数据可能只有部分是目标数据。

有人会说,可以在爬完数据之后再处理。也不是不可以,不过这个过程中调用api,io操作费时费力。

当前我想到的办法是,根据原文方法拿到要爬取的区域之后,先判断是否是我们想要的区域(方形区域4个点至少有一个在目标区域内),否则就舍弃掉。比如上图右上角的区域,拿到之后发现都是北京的,舍弃。

具体方法还要调用百度或高德提供的逆地理编码接口。点这里看介绍。

根据区域的location,调用接口,得到返回的数据中会包含该location的country、province、city等。然后进行过滤就OK了。

优化核心类似:之前目标区域划分成的小矩形块有10万个,根据逆地理编码接口,过滤掉其他省市,剩余5千个,获取这5千个小矩形块的poi数据即可。

我当前的应用中,因为涉及到北京市,所以划分的小矩形块和目标小矩形块差异较大,类似下图:

© 著作权归作者所有

chro008

chro008

粉丝 5
博文 51
码字总数 20427
作品 0
海淀
程序员
私信 提问
加载中

评论(28)

叫我哀木涕
叫我哀木涕
可以,很好用。多谢楼主!!
肖琦思俪
肖琦思俪
您好,那个网站打不开
chro008
chro008 博主

引用来自“肖琦思俪”的评论

您好,您这个拾取目标区域坐标是用百度地图?

引用来自“chro008”的评论

http://api.map.baidu.com/lbsapi/getpoint/index.html 百度有个坐标拾取系统

引用来自“肖琦思俪”的评论

高德地图也能拾取坐标,为啥不直接使用高德地图呢,我是新手,见谅哈。您好,是这样的,我现在通过python可以查询到高德地图某个区的某一类poi,但是有的区某一类poi超过了900个,所以想问下这个怎么解决,想着通过将某个区划分为几块,然后查询每一块的poi,不知到怎么实现,我看了下高德地图,好像行政区域,到不了街道的polyline经纬度。我是新手,只会直接摘抄代码运行,还不太懂原理。
我将目标区域(矩形) 在长宽的中点处作为划分的点,类似文中 “划分前” “划分后” 的草图
肖琦思俪
肖琦思俪

引用来自“肖琦思俪”的评论

您好,您这个拾取目标区域坐标是用百度地图?

引用来自“chro008”的评论

http://api.map.baidu.com/lbsapi/getpoint/index.html 百度有个坐标拾取系统
高德地图也能拾取坐标,为啥不直接使用高德地图呢,我是新手,见谅哈。您好,是这样的,我现在通过python可以查询到高德地图某个区的某一类poi,但是有的区某一类poi超过了900个,所以想问下这个怎么解决,想着通过将某个区划分为几块,然后查询每一块的poi,不知到怎么实现,我看了下高德地图,好像行政区域,到不了街道的polyline经纬度。我是新手,只会直接摘抄代码运行,还不太懂原理。
chro008
chro008 博主

引用来自“肖琦思俪”的评论

您好,您这个拾取目标区域坐标是用百度地图?
http://api.map.baidu.com/lbsapi/getpoint/index.html 百度有个坐标拾取系统
肖琦思俪
肖琦思俪
您好,您这个拾取目标区域坐标是用百度地图?
chro008
chro008 博主

引用来自“ln宁”的评论

我想请教一下作者,代码用了Thread.sleep(50)这句话,代码不是单线程的吗,这句话有什么意义呢?如果数据没有返回来,线程不会往下执行的,我是这么理解的
因为高德提供的api接口有QPS(每秒查询次数)限制,具体可以参考高德地图流量限制说明:https://lbs.amap.com/api/webservice/guide/tools/flowlevel
chro008
chro008 博主

引用来自“l_brain”的评论

请问源码下载了后怎么运行?
需要修改几个地方,比如你要爬取区域的经纬度坐标、你的高德账号ak等
l
ln宁
我想请教一下作者,代码用了Thread.sleep(50)这句话,代码不是单线程的吗,这句话有什么意义呢?如果数据没有返回来,线程不会往下执行的,我是这么理解的
l
l_brain
请问源码下载了后怎么运行?
GIS热力图制作与位置大数据分析

最近有很多朋友咨询位置数据、热力图等等东西,我一一进行了解答,但是个人精力实在有限,特写一个博客进行详细技术说明,其实这个东西位置数据、百度地图POI、高德地图POI等数据爬取、存储都...

osc_3dxe2p2c
2019/04/01
3
0
关于用OpenLayer实现加载高德地图实时路况的一个尝试

更新于2019-03-04 前言:前一段时间,我在一个交流群里发了一个关于用python爬取百度地图的一个poi点,群里有一个人说,如果你能爬取高德地图的车流量我可以帮你介绍工作,帮一个大学教授那工...

osc_v22siqak
2018/08/23
6
0
百度&高德地图小区景点边界轮廓实现

经常的我们在使用地图功能时,会发现在选择一个小区或者一个热门景点的时候,地图上面会给出其边界轮廓,能够方便我们知道其范围大小,有时候在我们使用地图组件的时候,也会面临着类似的需求...

osc_vsbo2lb1
2018/10/19
10
0
JS爬取高德地图地址信息(周边设施经纬度)

需求:给定进百万小区名称及对应城市信息,通过高德获取其周边设施信息(交通、医疗、教育、生活设施) 高德JS API 爬取灵感来自高德开发支持的JS API,当然你也可以直接调用高德提供的api服...

osc_1i3i83o4
2019/09/21
3
0
使用python及百度API对百度poi数据进行爬取(一)

档案系统初期算是告一段落了,利用一点时间继续爬取POI。和领导聊聊,受益匪浅。之前我的想法是爬取一份poi数据,直接能用;而领导听了之后,觉得更好的方式是爬取多个渠道来源的POI数据,然...

u010723516
2017/06/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

什么是 PL/SQL? 怎么用?

PL/SQL 1.什么是PL/SQL? PL/SQL(Procedure Language/SQL)是Oracle对sql语言的过程化扩展,指在SQL命令语言中增加了过程处理语句(如分支/条件、循环、变量、类型等),使SQL语言具有过程处...

煌sir
51分钟前
109
0
dayjs时间处理库基本使用

Day.js 是一个轻量的 JavaScript 时间日期处理库,与 Moment.js 的 API 设计保持一致。 本文只介绍了一些常用操作,关于国际化、插件、自定义等高级内容详见官方文档。 其主要特性如下: 与 ...

whoru
54分钟前
11
0
Delphi xe使用TJSONObject解析JSON数据

在Delphi 10 Seattle中重写 “ 使用TJSONObject分析JSON数据 ”。 由于不推荐使用某些方法,因此已对其进行了更改。 要使用TJSONObject,请添加“ System.JSON”。 uses System.JSON; 使用T...

simpower
今天
11
0
树莓派使用 OLED 屏显示图片及文字

树莓派默认是不带显示屏的,如果想要查看系统的一些信息,需要使用电脑登录到树莓派,或者通过 HDMI 连接外接显示器查看。这样做总是有点麻烦,我们可以通过外接一个 OLED 屏来显示一些关键参...

良许Linux
今天
13
0
BIO学习

1. BIO介绍 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程...

steven-黄笑笑
今天
13
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部