通過地址獲得經緯度(百度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+"\r\n");
                }
            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] +"\n";
        }
    }
    
    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

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM