zoukankan      html  css  js  c++  java
  • 通过地址获得经纬度(百度Geocoding API)

    1.什么是Geocoding?

    Geocoding API 是一类简单的HTTP接口,用于提供从地址到经纬度坐标或者从经纬度坐标到地址的转换服务,用户可以使用C# 、C++、Java等开发语言发送HTTP请求且接收JSON、XML的返回数据。

    2.功能介绍

    Geocoding API包括地址解析和逆地址解析功能。

    • 地理编码:即地址解析,由详细到街道的结构化地址得到百度经纬度信息,且支持名胜古迹、标志性建筑名称直接解析返回百度经纬度。例如:“北京市海淀区中关村南大街27号”地址解析的结果是“lng:116.31985,lat:39.959836”,“百度大厦”地址解析的结果是“lng:116.30815,lat:40.056885”
    • 逆地理编码,即逆地址解析,由百度经纬度信息得到结构化地址信息。例如:“lat:31.325152,lng:120.558957”逆地址解析的结果是“江苏省苏州市虎丘区塔园路318号”。
    3.如何使用

    百度地图Geocoding API是一套免费对外开放的API,无使用次数限制。使用方法:

    第一步:申请ak(即获取密钥),若无百度账号则首先需要注册百度账号

    第二步,拼写发送http请求的url,注意需使用第一步申请的ak。

    第三步,接收http请求返回的数据(支持json和xml格式)。

    以下是一个关于地理编码的简单示例。发送一个地址是“百度大厦”的请求,返回该地址对应的地理坐标。发送请求的url如下:

    http://api.map.baidu.com/geocoder/v2/?address=百度大厦&output=json&ak=E4805d16520de693a3fe707cdc962045&callback=showLocation 
    4.java调用测试
     1 package addressToGeoTest;
     2 
     3 import java.io.BufferedReader;
     4 import java.io.BufferedWriter;
     5 import java.io.File;
     6 import java.io.FileInputStream;
     7 import java.io.FileOutputStream;
     8 import java.io.IOException;
     9 import java.io.InputStreamReader;
    10 import java.io.OutputStreamWriter;
    11 import java.net.URL;
    12 import java.net.URLEncoder;
    13 import java.util.*;
    14 
    15 public class GetLatAndLngByBaidu {
    16  
    17  public static void main(String args[]){
    18      
    19      String cnAddress="北京市海淀区上地十街10号";
    20      Map<String,String> map = GetLatAndLngByBaidu.getLatitude(cnAddress);
    21         if(null != map){
    22             System.out.println(cnAddress+"    经度:"+map.get("lng")+"    纬度:"+map.get("lat"));
    23         }
    24  }
    25  /**
    26   * 返回输入地址的经纬度坐标
    27   * lng(经度),lat(纬度)
    28   */
    29  //1,申请ak(即获取密钥),若无百度账号则首先需要注册百度账号。
    30  public static final String AK= "VGqyTtpnqfNxkTkPBG5APrGO"; 
    31  public static Map<String,String> getLatitude(String address){
    32       try {
    33        address = URLEncoder.encode(address, "UTF-8");          //将地址转换成utf-8的16进制
    34           //2, 拼写发送http请求的url,注意需使用第一步申请的ak。
    35           //3, 接收http请求返回的数据(支持json和xml格式)本次采用json形式
    36        URL resjson = new URL("http://api.map.baidu.com/geocoder/v2/?address="
    37                           + address +"&output=json&ak="+ AK); 
    38        BufferedReader in = new BufferedReader(
    39                           new InputStreamReader(resjson.openStream()));
    40        String res;
    41        StringBuilder sb = new StringBuilder("");
    42        while((res = in.readLine())!=null){
    43         sb.append(res.trim());
    44        }
    45        in.close();
    46        String str = sb.toString();
    47        //System.out.println("return json:"+str);
    48        Map<String,String> map = null;
    49        if(str!=null){
    50         int lngStart = str.indexOf("lng":");
    51         int lngEnd = str.indexOf(","lat");
    52         int latEnd = str.indexOf("},"precise");
    53         if(lngStart > 0 && lngEnd > 0 && latEnd > 0){
    54          String lng = str.substring(lngStart+5, lngEnd);
    55          String lat = str.substring(lngEnd+7, latEnd);
    56          map = new HashMap<String,String>();
    57          map.put("lng", lng);
    58          map.put("lat", lat);
    59          return map;
    60         }
    61        }
    62       }catch (Exception e) {
    63        e.printStackTrace();
    64       }
    65       return null;
    66      }
    67 }
    View Code

    运行结果:

    5.简单应用

    期望实现功能:

    input.txt存放中文地址
    从input.txt中读取中文地址,获得经纬度
    将中文地址以及经纬度输出到output.txt中
    package addressToGeo;
    
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.net.URL;
    import java.net.URLEncoder;
    import java.util.*;
    
    public class GetLatAndLngByBaidu {
     
     public static void main(String args[]){
         
        long startTime=System.currentTimeMillis(); 
        String fileSourcePath="F://Essex//AddressToGeo//source//input.txt";
        String fileDestPath="F://Essex//AddressToGeo//source//output.txt";
        readAddressWriteGeo(fileSourcePath,fileDestPath);
       
     }
     /**
      * 返回输入地址的经纬度坐标
      * key lng(经度),lat(纬度)
      */
     //1,申请ak(即获取密钥),若无百度账号则首先需要注册百度账号。
     public static final String AK= "VGqyTtpnqfNxkTkPBG5APrGO"; 
     public static Map<String,String> getLatitude(String address){
          try {
           address = URLEncoder.encode(address, "UTF-8");          //将地址转换成utf-8的16进制
              //2, 拼写发送http请求的url,注意需使用第一步申请的ak。
              //3, 接收http请求返回的数据(支持json和xml格式)本次采用json形式
           URL resjson = new URL("http://api.map.baidu.com/geocoder/v2/?address="
                              + address +"&output=json&ak="+ AK); 
           BufferedReader in = new BufferedReader(
                              new InputStreamReader(resjson.openStream()));
           String res;
           StringBuilder sb = new StringBuilder("");
           while((res = in.readLine())!=null){
            sb.append(res.trim());
           }
           in.close();
           String str = sb.toString();
           //System.out.println("return json:"+str);
           Map<String,String> map = null;
           if(str!=null){
            int lngStart = str.indexOf("lng":");
            int lngEnd = str.indexOf(","lat");
            int latEnd = str.indexOf("},"precise");
            if(lngStart > 0 && lngEnd > 0 && latEnd > 0){
             String lng = str.substring(lngStart+5, lngEnd);
             String lat = str.substring(lngEnd+7, latEnd);
             map = new HashMap<String,String>();
             map.put("lng", lng);
             map.put("lat", lat);
             return map;
            }
           }
          }catch (Exception e) {
           e.printStackTrace();
          }
          return null;
         }
     /*
      *void readAddressWriteGeo(String sourceFilePath,String destFilePath) 函数
      *功能:从sourceFilePath下读取中文地址,获取经纬度,存放在destFilePath中
      * */
     public static void readAddressWriteGeo(String sourceFilePath,String destFilePath)
     {
         long startTime=System.currentTimeMillis(); 
         try
         {
             System.out.println("读取中文地址...");
            String encoding="Unicode";
            File fileSource=new File(sourceFilePath);//获得输入句柄
            FileInputStream fis=new FileInputStream(fileSource);//创建字节流输入对象
            InputStreamReader inStream=new InputStreamReader(fis,encoding);//将字节流转换为字符流,编码格式为Unicode,创建字节流输入对象
            BufferedReader input=new BufferedReader(inStream);
            
            String outputFilePath=createFile(destFilePath);
            File fileDest=new File(outputFilePath);//获得输出文件句柄
            FileOutputStream fos=new FileOutputStream(destFilePath);//创建字节流输出对象
            OutputStreamWriter outStream=new OutputStreamWriter(fos,encoding);//将字节流转换为字符流,编码格式为Unicode,创建字节流输出对象
            BufferedWriter output=new BufferedWriter(outStream);
            
            String cnAddress=null;
            cnAddress=input.readLine();
            System.out.println("通过百度api获取经纬度...");
            int count=0;
            while(cnAddress!=null)
            {
                //System.out.println(cnAddress);
                 Map<String,String> map = GetLatAndLngByBaidu.getLatitude(cnAddress);
                    if(null != map){
                        //System.out.println("经度:"+map.get("lng"));
                       //System.out.println("纬度:"+map.get("lat"));
                       output.write(map.get("lng")+"    "+map.get("lat")+"    "+cnAddress+"
    ");
                    }
                cnAddress=input.readLine();
                count++;
            }
            input.close();
            output.close();
            
            System.out.println("获取:"+count+"条经纬度信息");
            long endTime=System.currentTimeMillis();
            System.out.println("花费时间: "+(endTime-startTime)/1000+"s");
            System.out.println("经纬度获取成功!");
         }
         catch(IOException e)
         {
             e.printStackTrace();
         }
     }
     //创建新的output.txt文档
     public static String createFile(String filePath)
     {
        File f=new File(filePath);//构造一个路径的句柄
        if(f.exists())//如果文件存在则删除,不存在则生成
        {
            f.delete();
        }
        else
        {
            try {
                f.createNewFile();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return f.getPath();
     }
    
    }
    View Code

    运行测试结果:

     

    6.改进

    上面的解决方案使用单线程,数据量小的情况下还可以勉强使用。但是当数据量巨大时,耗时就非常的长(测试使用15000条地址数据差不多用了1小时)。考虑到耗费的时间主要花费在获取经纬度时服务器的响应上,因此考虑使用多线程。

    从input.txt读入,然后将地址信息切分为多个数组,为每一个数组开一个线程,转换后统一输出到output.txt

    实现代码:

    package addressToGeo;
    
    import java.io.*;
    import java.net.URL;
    import java.net.URLConnection;
    import java.net.URLEncoder;
    import java.util.HashMap;
    import java.util.Map;
    
    class MyThread extends Thread{
        private String[] GpsAdd;
        private static String AK = "NXlvvuBhTW1Bd7PaatQvyceV";
        private String name = "";
        private String[] Addmat = {" "};
        private int MatLen=0;
        public MyThread(String Name, String[] AddMat){
            this.name=Name;    
            this.Addmat = AddMat;
        }    
        public MyThread(){        
        }
        public String[] getGpsAdd(){
            return GpsAdd;
        }
        public void run(){        
            MatLen = Addmat.length;
            GpsAdd = new String[MatLen];
            for(int i=0;i<MatLen;i++){
                Map<String,String> map = getLatitude(Addmat[i]);
                System.out.println(this.name +": " + map.get("lng") + "  " + map.get("lat")+ "  " + Addmat[i] );
                GpsAdd[i] = map.get("lng") + "  " + map.get("lat")+ "  " + Addmat[i] +"
    ";
            }
        }
        
        public static Map<String,String> getLatitude(String address){
            
            Map<String,String> map = new HashMap<String,String>();
            try {
                address = URLEncoder.encode(address, "UTF-8");        
                URL resjson = new URL("http://api.map.baidu.com/geocoder/v2/?address="
                                        + address +"&output=json&ak="+ AK); 
                URLConnection uc=resjson.openConnection();
                uc.setConnectTimeout(1000*100);
                uc.setReadTimeout(1000*100);
                BufferedReader in = new BufferedReader(
                        new InputStreamReader(uc.getInputStream()));
                
                String res;
                StringBuilder sb = new StringBuilder("");
                while((res = in.readLine())!=null){
                    sb.append(res.trim());
                    }
                in.close();
                String str = sb.toString();
            
           if(str!=null){
               int lngStart = str.indexOf("lng":");
               int lngEnd = str.indexOf(","lat");
               int latEnd = str.indexOf("},"precise");
               if(lngStart > 0 && lngEnd > 0 && latEnd > 0){
                   String lng = str.substring(lngStart+5, lngEnd);
                   String lat = str.substring(lngEnd+7, latEnd);
                   
                   map.put("lng", lng);
                   map.put("lat", lat);
                  
                   }
               }
           }catch (Exception e) {
               e.printStackTrace();
               }
             return map;
            }
        public static String createFile(String filePath)
        {
            File f = new File(filePath);
            if(f.exists()) { 
                f.delete();
                }
            else
            {
                try {
                    f.createNewFile();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();        
                        }
            }
            return f.getPath();
        }
    }
    View Code
    package addressToGeo;
    
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.io.UnsupportedEncodingException;
    import java.net.URL;
    import java.net.URLEncoder;
    import java.util.*;
    
    public class GetLatAndLngByBaidu {
        
        private static int NumOfThread = 100;
        static String fileSourcePath="F://Essex//AddressToGeoAll//source//input.txt";
        static String fileDestPath="F://Essex//AddressToGeoAll//source//output.txt";
        
        public static void main(String args[]) throws InterruptedException, IOException{
            long startTime=System.currentTimeMillis();     
            threadStart(startTime);
        }
    public static void threadStart(long startTime) throws InterruptedException, IOException
    {
            System.out.println("start...");
            String cnAdd ="";
            int cnLen = 0;
            cnAdd = readAdd(fileSourcePath);
            String[] AddStr = cnAdd.split(",");
            cnLen = AddStr.length;
            System.out.println("get "+cnLen+" chinese address successful...");
            System.out.println("to get longitude and latitude ...");
            int MatLen = cnLen/NumOfThread;
            String [][] sp=new String[NumOfThread][MatLen];
            MyThread [] mt=new MyThread[NumOfThread];
            for(int j=0;j<NumOfThread;j++)
            {
                sp[j]=new String[MatLen];
                for(int i=0;i<MatLen;i++)
                {
                    sp[j][i]=AddStr[i+j*MatLen];
                }
                mt[j]=new MyThread("线程"+j,sp[j]);
                mt[j].start();
            }
            
            for(int j=0;j<NumOfThread;j++)
            {
                mt[j].join();
            }
            String[] result;
            FileWriter letter = new FileWriter(fileDestPath);
            
            for(int j=0;j<NumOfThread;j++)
            {
                result = mt[j].getGpsAdd();
                writeFile(result,letter,MatLen);    
            }
            
            //处理结尾由于不能被100整数引起多余的几个数据
            if(NumOfThread*MatLen <= cnLen-1){
                    String[] LastMat = new String[cnLen-NumOfThread*MatLen];
                    for(int i =0;i<cnLen-NumOfThread*MatLen;i++){
                        LastMat[i] = AddStr[NumOfThread*MatLen+i];
                    }
                    MyThread LastThread = new MyThread("线程last",LastMat);
                    LastThread.start();
                    LastThread.join();
                    result = LastThread.getGpsAdd();
                    writeFile(result, letter, cnLen-NumOfThread*MatLen);
                }
        letter.close();
        getExcuteTime(startTime);
    }
    
     //1,申请ak(即获取密钥),若无百度账号则首先需要注册百度账号。
     public static final String AK= "NXlvvuBhTW1Bd7PaatQvyceV"; 
     public static String readAdd(String sourceFilePath){
         try{
             String encoding="Unicode";
             File fileSource=new File(sourceFilePath);//获得输入句柄
             FileInputStream fis=new FileInputStream(fileSource);//创建字节流输入对象
             InputStreamReader inStream=new InputStreamReader(fis,encoding);//将字节流转换为字符流,编码格式为Unicode,创建字节流输入对象
             BufferedReader input=new BufferedReader(inStream);        
             
             String cnAddress=null;
             cnAddress=input.readLine();
             StringBuilder sb = new StringBuilder("");
             while(cnAddress!=null){
                sb.append(cnAddress.trim());
                sb.append(",");
                cnAddress=input.readLine();
             }
             String sbStr = sb.toString();
        //     System.out.println(sb.toString()); //输出所有地址
             input.close();
             return sbStr;
         } catch (IOException e){
             e.printStackTrace();
         }
         return null;
     }
     public static void getExcuteTime(long startTime)
     {
         long endTime=System.currentTimeMillis();
         long time=endTime-startTime;
         System.out.println("take time: "+time/1000+" second");
         System.out.println("about "+time/1000/60+" minute");
     }
     public static void writeFile(String[] result, FileWriter writer, int MatLen) throws IOException{    
            for(int i = 0;i<MatLen;i++){
                writer.write(result[i]);;
            }
        }
    }
    View Code
    7.不足

    1,网速不好的情况下,开100个线程会出现 java.net.SocketTimeoutException: connect timed out错误。

    虽然使用了uc.setConnectTimeout(10000);   uc.setReadTimeout(10000); 但是没有起到效果。(求改进)

    2,所有的数据都会放在内存上,当数据量到达千万级别时候,会内存不足。(求改进)

    8.引用

    http://developer.baidu.com/map/webservice-geocoding.htm  

    http://www.cnblogs.com/gzggyy/archive/2013/06/21/3148610.html

    http://lavasoft.blog.51cto.com/62575/99150

    http://www.360doc.com/content/13/0422/09/3776353_280044198.shtml

     
  • 相关阅读:
    Visitor Pattern (Visitor设计模式)
    JS DatePicker: jscalendar1.0___v1.51 (JS日期选择器)
    转:Mediator模式
    转: Debug with IIS Express
    101 LINQ Samples
    关于进程与线程:About Processes and Threads
    转:PureMVC示例 CafeTownsend
    Haskell Editor:Leksah & EclipseFP The Haskell plugin for Eclipse
    Haskell、C#、Java、C 程序执行效率比较 :Write your first parallel Haskell program
    SCJP: java exerciese 1
  • 原文地址:https://www.cnblogs.com/qianwen/p/3908396.html
Copyright © 2011-2022 走看看