java爬取高德地图poi(兴趣点)_无需注册开发者账号

因项目需要爬取XX市XX区的poi信息,上网找了很多的教程,都需要注册高德的开发控制台,通过调用高德提供的api方式获取poi信息,但是有次数限制。所以自己搞了个"爬虫"。

1、思路:

打开高德地图浏览时,拖地地图,会调用https://ditu.amap.com/service/regeo?longitude=XXX&latitude=XXX接口,此接口是不需要鉴权的,该接口的作用是定位,将你所处位置的gps点输入进去后,将会返回附近的几个定位点。思路油然而生,我将所要爬取范围的所有gps点一个个的调用这个接口,不就可以获取到这个区域的poi信息了嘛,说干就干

2、代码及说明

写代码前考虑一个问题,如果是爬某个区,但是这个区在地图上的形状是不规则的,怎么办?用个矩形将不规则图形包围起来嘛,简单!但是效率低,我也懒得去研究其他方法,也别想其他方法了,因为接口调用是有限制的,同一ip开多线程去调用,会被封ip和mac地址(我已经被封了,幸好我机智,发现了另外一个,第一个:https://www.amap.com/ ,第二个:https://ditu.amap.com/)。如果你有代理ip池,当我没说,将你的地图分割成一个个小的矩形,分别用多线程尽情去轰炸高德的两个域名把。

(1)我是将爬取到的数据放到mysql数据库中,上sql和代码:

sql

CREATE TABLE `t_poi` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `x` varchar(50) DEFAULT NULL,
  `y` varchar(50) DEFAULT NULL,
  `type` varchar(255) DEFAULT NULL,
  `address` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4571 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

dbUtil:

package com.cm.test1.poi;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

public class DbUtil {
    public static final String URL = "jdbc:mysql://xx.xx.xx.xx:3306/xx";
    public static final String USER = "root";
    public static final String PASSWORD = "root";
    private static Connection conn = null;
    static{
        try {
            //1.加载驱动程序
            Class.forName("com.mysql.cj.jdbc.Driver");
            //2. 获得数据库连接
            conn = DriverManager.getConnection(URL, USER, PASSWORD);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection(){
        return conn;
    }

    public static String insert="INSERT INTO `cm`.`t_poi`( `name`, `x`, `y`, `type`, `address`) VALUES ('%s', '%s', '%s', '%s', '%s')";
    public static String query="select count(1) count from t_poi where name = '%s' ";

    public static void create(String name,String x,String y,String type,String address)
        throws SQLException {
        Connection conn= getConnection();
        String sql=String.format(insert,name,x,y,type,address);
        PreparedStatement ptmt = conn.prepareStatement(sql);
        ptmt.execute();
    }

    public static boolean query(String name) throws SQLException {
        Connection conn= getConnection();
        String sql=String.format(query,name);
        PreparedStatement ptmt = conn.prepareStatement(sql);
        ResultSet rs= ptmt.executeQuery();
        while(rs.next()){

           return  rs.getInt("count")==1?true:false;
        }
        return false;
    }
}

main方法:

package com..cm.test1.poi;/*

import cn.hutool.db.DbUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;


*/
/**
 * @Description
 * @Author zhangchuang
 * @Date 2020/5/25 5:38 下午
 **//*

public class GusuShang {

  static RestTemplate restTemplate = new RestTemplate();

  static HttpEntity<MultiValueMap<String, String>> httpEntity;

  static {
    HttpHeaders header = new HttpHeaders();
    MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
    map.add("Connection", "keep-alive");
    map.add("Accept-Language", "zh-CN,zh;q=0.9");

    // 需求需要传参为form-data格式
    header.setContentType(MediaType.MULTIPART_FORM_DATA);
    httpEntity = new HttpEntity<>(map, header);
  }


  public static void main(String[] args) throws IOException, InterruptedException, SQLException {


    minX = 150.267134;
    maxY = 36.511519;

    minY = 36.219654;
    maxX = 150.122539;

    //String url = "https://www.amap.com/service/regeo?longitude=%s&latitude=%s";

    String url = "https://ditu.amap.com/service/regeo?longitude=%s&latitude=%s";
    double value = 0.0001;

    long count = 0;

    for (double i = maxY; i >= minY; i -= value) {

      for (double j = minX; j <= maxX; j += value) {

        count++;

        JSONObject jsonObject = httpGet(url, j, i);

        if (ObjectUtils.isEmpty(jsonObject) || jsonObject.getInteger("status") != 1) {

          System.out.println("调用接口返回值为 null" + jsonObject);

        } else {

          System.out.println("调用接口返回值为 " + jsonObject.toJSONString());

          if (!"XX区".equals(jsonObject.getJSONObject("data").getString("district"))) {
            continue;
          }

          JSONArray jsonArray = jsonObject.getJSONObject("data").getJSONArray("poi_list");

          if (ObjectUtils.isEmpty(jsonArray)) {
            System.out.println("jsonArray is empty");
            continue;
          }

          int size = jsonArray.size();

          for (int k = 0; k < size; k++) {

            try {

              JSONObject jo = jsonArray.getJSONObject(k);
              String name = jo.getString("name");

              if (DbUtil.query(name)) {
                continue;
              }

              String type = jo.getString("type");
              String x = jo.getString("longitude");
              String y = jo.getString("latitude");
              String address = jo.getString("address");

              DbUtil.create(name, x, y, type, address);

            } catch (Exception e) {

              System.out.println(e);

            }
          }
        }
      }

    }

    System.out.println("count=" + count);


  }


  static JSONObject httpGet(String url, double x, double y) throws IOException {

    try {
      url = String.format(url, (x + "").substring(0, 10), (y + "").substring(0, 9));

      JSONObject jsonObject = restTemplate.getForObject(url, JSONObject.class, httpEntity);

      return jsonObject;
    } catch (Exception e) {
      System.out.println(e);
    }
    return null;
  }


  static class Point {

    double x;
    double y;

    public Point(double x, double y) {
      this.x = x;
      this.y = y;
    }

    public double getX() {
      return x;
    }

    public void setX(double x) {
      this.x = x;
    }

    public double getY() {
      return y;
    }

    public void setY(double y) {
      this.y = y;
    }

    @Override
    public String toString() {
      return "Point{" +
          "x=" + x +
          ", y=" + y +
          '}';
    }
  }
}

(2)代码简单说明和需要改动的参数说明
2.1、sql和DbUtil没什么好说的吧,简单的sql和jdbc连接。
2.2、下面说mian中的参数
2.3、

minX = 120.577235;
maxY = 31.271818;

minY = 31.269659;
maxX = 120.662379;

minX是矩形在地图左上角点位的经度
maxY是矩形在地图左上角点位的纬度
maxX是矩形在地图右下角点位的经度
minY是矩形在地图左上角点位的纬度
地图
哦对,还有个高德地图点位拾取的工具:
https://lbs.amap.com/console/show/picker
点击页面就可以在网站的上半部分看到点击的gpw点位。

2.4、

		//String url = "https://www.amap.com/service/regeo?longitude=%s&latitude=%s";

    	String url = "https://ditu.amap.com/service/regeo?longitude=%s&latitude=%s";

当第一个被封了之后,切换第二个,两个效果一样
2.5、

		    double value = 0.0001;

这个值是决定了统计的经度,值越小,粒度越细,收集到的点位越多,但是循环此处会呈几何倍数的增长,慎重修改。我目前是经纬度共用了这一个值,也可以将经纬度使用不同的值控制,自行修改。

2.6、

if (!"XX区".equals(jsonObject.getJSONObject("data").getString("district"))) {
            continue;
          }

如果是想要爬取某个区的poi点,需要修改XX区的值,因为矩形框会包括其他区域,所以需要过滤下,如果不考虑,则注释掉,否则会将爬取维度定为”区“。如果想爬多个区,就修改下if的条件,将多个区放在list中,用contains来判断。

3、总结

可能我这个不是啥好东西,但是我确实用这个方法爬出了一个区5000多个高质量定位,商户信息爬的比较少,大的建筑基本都能爬到,不同需求不同处理方法,希望对你有用,谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值