Small class | get the city name according to ip

Posted by sweetstuff2003 on Tue, 16 Nov 2021 08:45:57 +0100

In some scenarios, we need to obtain the corresponding city name according to ip. For example, we need to count the distribution of access ip in various cities; For example, in the Internet of things environment, equipment access is counted according to the city dimension.

So far, many open interfaces, such as Taobao, Sina, Tencent and Baidu, have failed or need key. Many interfaces are no longer called for free. This article provides three methods:

  • Use inexplicable API
  • Using Ip2Region
  • Use the GeoIp offline package provided by MaxMind

1. Use inexplicable API

Inexplicable API introduction

visit https://api.qzone.work/doc/ipaddress.html Yes. The format of the returned result is as follows:

{
  "msg":"success",
  "code":10000,
  "data":{
    "country":"China",
    "province":"Guangdong Province",
    "city":"Shenzhen City",
    "ip":"101.105.35.57",
    "ISP":"Dr. Peng"
  },
  "time":0.00932,
  "info":"Welcome to inexplicable blog(Qzone.Work)Free of charge API service!"
}

Code steps

1. Build the HttpClient object and call the URL address of the inexplicable API

    String url = "https://api.qzone.work/api/ip.address?ip="+ip;
    String cityName = "";
    HttpClient client = HttpClientBuilder.create().build();
    HttpGet request = new HttpGet(url);

2. Just parse the returned json string

    HttpResponse response = client.execute(request);
    int statusCode = response.getStatusLine().getStatusCode();
    if (statusCode == HttpStatus.SC_OK) {
        String strResult = EntityUtils.toString(response.getEntity());
          JSONObject jsonResult = JSON.parseObject(strResult);
          System.out.println(JSON.toJSONString(jsonResult, true));
          JSONObject dataJson = jsonResult.getJSONObject("data");
          cityName = dataJson.getString("city");
     }
 ... ...

2. Using ip2region

Ip2region - an offline IP address location library with an accuracy of 99.9%. It has a 0.0x millisecond query. The ip2region.db database has only a few MB. It provides query binding in java,php,c,python,nodejs,golang,c# and three query algorithms: Binary,B-tree and memory.

Each ip data segment has a fixed format:

_city Id|country|region|province|city|ISP_

If;

{
  "cityId":995,
  "dataPtr":117853,
  "region":"China|East China|Shanghai|Shanghai|move"
}

Code steps:

1. Prepare the DB file, such as creating the data directory under src/main/resource directory and storing the ip2region.db file

2. Introducing ip2region dependent packages

    <dependency>
      <groupId>org.lionsoul</groupId>
      <artifactId>ip2region</artifactId>
      <version>1.7.2</version>
    </dependency>

3. Read the ip2region.db file, specify the query algorithm, such as btreeSearch, and then obtain the data block result. The region of the block contains the city information.

    DbSearcher searcher = null;
    try {
      String dbPath = Ip2CityUtil.class.getClassLoader().getResource("data/ip2region.db").getPath();
      File file = new File(dbPath);
      if (file.exists()) {
        DbConfig config = new DbConfig();
        searcher = new DbSearcher(config, file.getPath());
        Method method = searcher.getClass().getMethod("btreeSearch", String.class);
        if (!Util.isIpAddress(ip)) {
         System.out.println("Error: Invalid ip address");
        }
        DataBlock dataBlock = (DataBlock) method.invoke(searcher, ip);
        System.out.println(JSON.toJSONString(dataBlock, true));
        return dataBlock.getRegion();
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
    return "";
  }

3. Using GeoLite2

Like ip2region, GeoLite2 prepares offline packets and imports dependent packets.

Code steps:

1. Prepare the db file, such as creating the data directory under src/main/resource directory and storing the GeoLite2-City.mmdb file

2. Introducing geolite 2 dependency package

  <dependency>
      <groupId>com.maxmind.geoip2</groupId>  
      <artifactId>geoip2</artifactId>
      <version>2.14.0</version>
  </dependency>

3. Read the GeoLite2-City.mmdb file, create the DatabaseReader object, and then obtain the CityResponse result through the reader.city method, which contains rich geographic location information.

public static String getCityNameByGeoLite2(String ip) {
    try {
      InputStream database = Ip2CityUtil.class.getClassLoader().getResourceAsStream("data/GeoLite2-City.mmdb");

      // Create DatabaseReader object
      DatabaseReader reader = new DatabaseReader.Builder(database).build();

      InetAddress ipAddress = InetAddress.getByName(ip);

      CityResponse response = reader.city(ipAddress);
      System.out.println(JSON.toJSONString(response, true));
      // System.out.println( response.getCity().getNames().get("zh-CN"));
      return response.getCity().getNames().get("zh-CN");
    } catch (Exception e) {
      e.printStackTrace();
    }
    return "";

  }

4. The content example of a CityResponse is as follows:

{
  "city":{
    "geoNameId":1796236,
    "name":"Shanghai",
    "names":{
      "de":"Shanghai",
      "ru":"Шанхай",
      "pt-BR":"Xangai",
      "ja":"Shanghai",
      "en":"Shanghai",
      "fr":"Shanghai",
      "zh-CN":"Shanghai",
      "es":"Shanghai"
    }
  },
  "continent":{
    "code":"AS",
    "geoNameId":6255147,
    "name":"Asia",
    "names":{
      "de":"Asien",
      "ru":"Азия",
      "pt-BR":"Ásia",
      "ja":"アジア",
      "en":"Asia",
      "fr":"Asie",
      "zh-CN":"Asia",
      "es":"Asia"
    }
  },
  "country":{
    "geoNameId":1814991,
    "inEuropeanUnion":false,
    "isoCode":"CN",
    "name":"China",
    "names":{
      "de":"China",
      "ru":"Китай",
      "pt-BR":"China",
      "ja":"China",
      "en":"China",
      "fr":"Chine",
      "zh-CN":"China",
      "es":"China"
    }
  },
  "leastSpecificSubdivision":{
    "geoNameId":1796231,
    "isoCode":"SH",
    "name":"Shanghai",
    "names":{
      "en":"Shanghai",
      "fr":"Municipalité de Shanghai",
      "zh-CN":"Shanghai",
      "pt-BR":"Xangai"
    }
  },
  "location":{
    "accuracyRadius":20,
    "latitude":31.0449,
    "longitude":121.4012,
    "timeZone":"Asia/Shanghai"
  },
  "maxMind":{

  },
  "mostSpecificSubdivision":{"$ref":"$.leastSpecificSubdivision"},
  "postal":{

  },
  "registeredCountry":{
    "geoNameId":1814991,
    "inEuropeanUnion":false,
    "isoCode":"CN",
    "name":"China",
    "names":{
      "de":"China",
      "ru":"Китай",
      "pt-BR":"China",
      "ja":"China",
      "en":"China",
      "fr":"Chine",
      "zh-CN":"China",
      "es":"China"
    }
  },
  "representedCountry":{
    "inEuropeanUnion":false,
    "names":{}
  },
  "subdivisions":[
    {"$ref":"$.leastSpecificSubdivision"}
  ],
  "traits":{
    "anonymous":false,
    "anonymousProxy":false,
    "anonymousVpn":false,
    "hostingProvider":false,
    "ipAddress":"183.194.238.19",
    "legitimateProxy":false,
    "network":{
      "networkAddress":"183.194.128.0",
      "prefixLength":17
    },
    "publicProxy":false,
    "satelliteProvider":false,
    "torExitNode":false
  }
}

You can obtain city information through response. Getcity(). Getnames(). Get ("zh CN"). For example, the above example obtains Shanghai.

4. Related Library Download

Resource download

https://pan.baidu.com/s/4pRI9z2F

The information of GeoLite2 is comprehensive, but its accuracy is not very accurate. ip2region is relatively accurate.