Java 获取安徽省所有的服务区、收费站、桥梁、隧道等经纬度信息

系列文章目录

第一章 开源GIS选型

第二章 Geoserver+QGis开发环境搭建

第三章 Openlayers前端接入

第四章 接入发布的离线瓦片

实战 抓取安徽省所有市、县、镇矢量坐标数据

Java精准地图坐标转换 高德 百度 谷歌 腾讯 高德 批量转换工具类达到项目生产精度

实战爬取【腾讯地图】上的收费站、服务区、厕所等数据

文章目录

前言

最近项目有个需求,需要画出安徽省所有的服务区收费站桥梁隧道等,Gis玩久了就知道了,有数据就很easy,但是可惜这个数据我们没有,买是不可能买的,那就另辟蹊径,所以我就从高德上爬了点儿(合法滴哦),效果图如下:

Java 获取安徽省所有的服务区、收费站、桥梁、隧道等经纬度信息

一、先去高德注册个账号

已有账号的直接跳过

  1. 首先,注册账号,成为高德开放平台开发者

  2. 登陆之后,在进入「应用管理」 页面「创建新应用」
    Java 获取安徽省所有的服务区、收费站、桥梁、隧道等经纬度信息

  3. 为应用添加 Key,「服务平台」一项请选择「 Web服务」
    Java 获取安徽省所有的服务区、收费站、桥梁、隧道等经纬度信息

二、通过高德POI接口抓取坐标数据

搜索POI接口文档非常的详细

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

适用场景

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

代码示例

依赖Jar,pom.xml

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.4.3</version>
        </dependency>

以抓取服务区为示例:

      /**
     * 获取兴趣点,例如交通上常用的服务区,收费站,桥梁,隧道等
     *
     * @param cityCode 为了您查询的精确,我们强烈建议您使用adcode。
     *                 安徽省 340000
     *                 可选值:城市中文、中文全拼、citycode、adcode
     *                 如:北京/beijing/010/110000
     *                 填入此参数后,会尽量优先返回此城市数据,但是不一定仅局限此城市结果,若仅需要某个城市数据请调用citylimit参数。
     *                 如:在深圳市搜*,返回北京*结果。
     * @param poiType  查询POI类型,建议分类代码
     *                 可选值:分类代码 或 汉字(若用汉字,请严格按照附件之中的汉字填写)
     *                 分类代码由六位数字组成,一共分为三个部分,前两个数字代表大类;中间两个数字代表中类;最后两个数字代表小类。
     *                 若指定了某个大类,则所属的中类、小类都会被显示。
     *                 例如:010000为汽车服务(大类)
     *                 010100为加油站(中类)
     *                 010101为中国石化(小类)
     *                 010900为汽车租赁(中类)
     *                 010901为汽车租赁还车(小类)
     *                 <p>
     *                 **POI分类编码****城市编码表**下载
     *                 <p>
     *                 https://lbs.amap.com/api/webservice/download
     */
    public static List getPoi(String cityCode, String poiType) throws Exception {
        /**
         *请求参数释义:
         *   citylimit: 仅返回指定城市数据 默认false
         *
         *   children: 是否按照层级展示子POI数据 默认0
         *           可选值:children=1
         *           当为0的时候,子POI都会显示。
         *           当为1的时候,子POI会归类到父POI之中。
         *           仅在extensions=all的时候生效
         *   offset: 每页记录数据 默认 20
         *           强烈建议不超过25,若超过25可能造成访问报错
         *   page: 当前页数 1
         *         最大翻页数100
         *   extensions: 返回结果控制 默认 base
         *          此项默认返回基本地址信息;取值为all返回地址信息、附近POI、道路以及道路交叉口信息。
         *结果释义:
         *    count:搜索方案数目(最大值为1000) 结果条数
         *    pois:搜索POI信息列表
         *      poi:POI信息
         *        id:唯一id "B023502FH9"
         *        name:名称 "沙溪服务区"
         *        type:兴趣点类型:"道路附属设施;服务区;高速服务区"
         *        address: 地址 "庐江县"
         *        location: 经纬度 "117.251487,31.1485"
         *        cityname: 城市名 "合肥市"
         *        adname: 区域名称 "庐江县"
         *        photos 照片相关信息 extensions=all 时返回
         */
        String url = "https://restapi.amap.com/v3/place/text?parameters?types={}&city={}&page={}&citylimit=true&extensions=all&offset=20&key=" + key;
        String jsonBody = "";
        Root root = null;
        List list = new ArrayList();
        for (int i = 1; i < 100; i++) {
            jsonBody = HttpUtil.createGet(StrUtil.format(url, poiType, cityCode, i)).execute().body();
            root = JSONUtil.toBean(jsonBody, Root.class);
            List<Poi> pois = root.getPois();
            if (CollUtil.isEmpty(pois)) {
                break;
            }
            list.addAll(pois);

        }
        return list;
    }

POI分类编码 城市编码表下载

三、把高德抓的数据转换为GeoJson格式的矢量数据

1、什么是GeoJson

GeoJSON是一种用于编码各种地理数据结构的格式。

{
  "type": "Feature",
  "geometry": {
    "type": "Point",
    "coordinates": [125.6, 10.1]
  },
  "properties": {
    "name": "Dinagat Islands"
  }
}

以GeoJSON支持以下几何类型:Point,LineString, Polygon,MultiPoint,MultiLineString,和MultiPolygon。具有其他属性的几何对象是Feature对象。要素集包含在FeatureCollection对象中。
参考

说白了就是特定格式的Json。

  • 来个体验的网站

GeoJson 在线生成测试地址分享:
http://geojson.io

2、按照GeoJson规范生成即可

我们需要的类型格式是下面这种,只要按照这种格式生成即可;

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "name": "123",
        "level": "test"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [
          113.84033203125,
          34.161818161230386
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "name": "123",
        "level": "test"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [
          117.6416015625,
          33.742612777346885
        ]
      }
    }
  ]
}

3、示例代码

 static final File geojsonFile = new File("D://test.geojson");

    private static void handleToGeoJson(List<Poi> pois) throws IOException {
        GeoJson geoJson = new GeoJson();
        geoJson.setName("安徽省市、县中心坐标");
        geoJson.setType("FeatureCollection");// 勿动
        List<Feature> features = new ArrayList<>();
        geoJson.setFeatures(features);
        pois.forEach(poi ->
        {
            Feature feature = new Feature();
            Map properties = new HashMap();
            properties.put("name", poi.getName());
            feature.setProperties(properties);
            Geometry geometry = new Geometry();
            List<Double> coordinates = new ArrayList<>();
            List<String> split = StrUtil.split(poi.getLocation(), ',');
            double[] doubles = CoordinateTransformUtil.gcj02towgs84(Double.valueOf(split.get(0)), Double.valueOf(split.get(1)));
            coordinates.add(doubles[0]);
            coordinates.add(doubles[1]);
            geometry.setCoordinates(coordinates);
            geometry.setType("Point");
            feature.setGeometry(geometry);
            features.add(feature);
        });
        String geoJsonString = JSONUtil.toJsonStr(geoJson);
        FileWriter writer = new FileWriter(geojsonFile);
        writer.write(geoJsonString);
    }

4、坐标系转换

因为我的底图是WGS84的,而高德抓取的是GCJ02的坐标系,所以需要转换,转换参考我的文章,有源码

Java精准地图坐标转换 高德 百度 谷歌 腾讯 高德 批量转换工具类达到项目生产精度

四、整体源码

public class GaodeGis {
    public static final String key = "用你自己的key";

    public static void main(String[] args) throws Exception {
        List list = getPoi("340000", "180300");
        System.out.println(list.size());
        handleToGeoJson(list);
    }

    /**
     * 获取兴趣点,例如交通上常用的服务区,收费站,桥梁,隧道等
     *
     * @param cityCode 为了您查询的精确,我们强烈建议您使用adcode。
     *                 安徽省 340000
     *                 可选值:城市中文、中文全拼、citycode、adcode
     *                 如:北京/beijing/010/110000
     *                 填入此参数后,会尽量优先返回此城市数据,但是不一定仅局限此城市结果,若仅需要某个城市数据请调用citylimit参数。
     *                 如:在深圳市搜*,返回北京*结果。
     * @param poiType  查询POI类型,建议分类代码
     *                 可选值:分类代码 或 汉字(若用汉字,请严格按照附件之中的汉字填写)
     *                 分类代码由六位数字组成,一共分为三个部分,前两个数字代表大类;中间两个数字代表中类;最后两个数字代表小类。
     *                 若指定了某个大类,则所属的中类、小类都会被显示。
     *                 例如:010000为汽车服务(大类)
     *                 010100为加油站(中类)
     *                 010101为中国石化(小类)
     *                 010900为汽车租赁(中类)
     *                 010901为汽车租赁还车(小类)
     *                 <p>
     *                 **POI分类编码****城市编码表**下载
     *                 <p>
     *                 https://lbs.amap.com/api/webservice/download
     */
    public static List getPoi(String cityCode, String poiType) throws Exception {
        /**
         *请求参数释义:
         *   citylimit: 仅返回指定城市数据 默认false
         *
         *   children: 是否按照层级展示子POI数据 默认0
         *           可选值:children=1
         *           当为0的时候,子POI都会显示。
         *           当为1的时候,子POI会归类到父POI之中。
         *           仅在extensions=all的时候生效
         *   offset: 每页记录数据 默认 20
         *           强烈建议不超过25,若超过25可能造成访问报错
         *   page: 当前页数 1
         *         最大翻页数100
         *   extensions: 返回结果控制 默认 base
         *          此项默认返回基本地址信息;取值为all返回地址信息、附近POI、道路以及道路交叉口信息。
         *结果释义:
         *    count:搜索方案数目(最大值为1000) 结果条数
         *    pois:搜索POI信息列表
         *      poi:POI信息
         *        id:唯一id "B023502FH9"
         *        name:名称 "沙溪服务区"
         *        type:兴趣点类型:"道路附属设施;服务区;高速服务区"
         *        address: 地址 "庐江县"
         *        location: 经纬度 "117.251487,31.1485"
         *        cityname: 城市名 "合肥市"
         *        adname: 区域名称 "庐江县"
         *        photos 照片相关信息 extensions=all 时返回
         */
        String url = "https://restapi.amap.com/v3/place/text?parameters?types={}&city={}&page={}&citylimit=true&extensions=all&offset=20&key=" + key;
        String jsonBody = "";
        Root root = null;
        List list = new ArrayList();
        for (int i = 1; i < 100; i++) {
            jsonBody = HttpUtil.createGet(StrUtil.format(url, poiType, cityCode, i)).execute().body();
            root = JSONUtil.toBean(jsonBody, Root.class);
            List<Poi> pois = root.getPois();
            if (CollUtil.isEmpty(pois)) {
                break;
            }
            list.addAll(pois);

        }
        return list;
    }

    static final File geojsonFile = new File("D://test.geojson");

    private static void handleToGeoJson(List<Poi> pois) throws IOException {
        GeoJson geoJson = new GeoJson();
        geoJson.setName("安徽省市、县中心坐标");
        geoJson.setType("FeatureCollection");// 勿动
        List<Feature> features = new ArrayList<>();
        geoJson.setFeatures(features);
        pois.forEach(poi ->
        {
            Feature feature = new Feature();
            Map properties = new HashMap();
            properties.put("name", poi.getName());
            feature.setProperties(properties);
            Geometry geometry = new Geometry();
            List<Double> coordinates = new ArrayList<>();
            List<String> split = StrUtil.split(poi.getLocation(), ',');
            double[] doubles = CoordinateTransformUtil.gcj02towgs84(Double.valueOf(split.get(0)), Double.valueOf(split.get(1)));
            coordinates.add(doubles[0]);
            coordinates.add(doubles[1]);
            geometry.setCoordinates(coordinates);
            geometry.setType("Point");
            feature.setGeometry(geometry);
            features.add(feature);
        });
        String geoJsonString = JSONUtil.toJsonStr(geoJson);
        FileWriter writer = new FileWriter(geojsonFile);
        writer.write(geoJsonString);
    }

}

总结

老哥们,如果你们因为本文起飞了,请原地全体起立,然后关注一波,加QQ群或者微信一起探讨工作日常和面试相关问题,和大家共同进步。


分享个很好用的免费工具
可以爬省市的矢量数据,以及各大厂商google、百度、高德等的瓦片数据
关注公众号【Java厂面试官】,回复:地图下载器
Java 获取安徽省所有的服务区、收费站、桥梁、隧道等经纬度信息


上一篇:微信小程序(小程序定位获取地址信息篇)


下一篇:记录-工具类-java读取pdf和word