[C#/Google ] IP、經緯度、中文地址互轉
現在開發地理資訊系統, 很難說以後不會遇到IP、經緯度、中文地址三者的互轉
最近做這方面的研究,把找到的方法都整理一下
1. 由IP取得經緯度和英文縣市(出處:Visual Studio 2010妙用錦囊)
Visual Studio 2010妙用錦囊使用的API已換新位址:http://freegeoip.net/static/index.html,而且只有英文結果
限制:每小時1000個查詢,超過的話會收到403禁止的訊息
Sample Code:
string myIP = "210.59.250.101";
protected void Page_Load(object sender, EventArgs e)
{
WebClient wc = new WebClient();
//wc.Encoding = Encoding.UTF8;
//wc.Headers.Add("Accept-Language:zh-tw");
string format = "json";//csv 或 xml
//取得原始結果
string json = wc.DownloadString("http://freegeoip.net/" + format + "/" + this.myIP);
//如果IP為空字串的話,預設會自動偵測抓Request的IP
//利用Json.net解析
JObject obj = JsonConvert.DeserializeObject<JObject>(json);
//取得經緯度
string lat = obj["latitude"].ToString();//緯度
string lng = obj["longitude"].ToString();
//取得英文縣市名稱
string city = obj["city"].ToString();//縣市名稱
Response.Write("縣市:"+city+"<hr/>");
Response.Write("經度:"+lng+",緯度:"+lat);
}
Google官方文件表示,使用IP來偵測使用者位置只能估計出約略結果,利用W3C制定的Geolocation API(HTML 5功能)才會得到比較完整精確的結果
以下是HTML5 Geolocation API範例(這篇圖文教學介紹的滿詳細:HTML5 Geolocation API 簡介)
使用限制:要注意部份瀏覽器才支援(因為是Html5功能),且javascript限定
<script type="text/javascript">
window.onload = function () {
//防呆
if (window.navigator.geolocation) {
window.navigator.geolocation.getCurrentPosition(success, error,
{
enableHighAccuracy: true, //取得高精確度的位置資訊
maximumAge: 0//馬上取得位置資訊
});
} else {
alert("瀏覽器不支援Html5的Geolocation API");
}
}
function success(position)
{
alert("緯度:" + position.coords.latitude+",經度:"+position.coords.longitude);
}
function error(e)
{
alert(e.message);
}
</script>
另外,雖然Google官方文件出現Google Gears Geolocation的範例,但其實Google Gears API已經無法使用了
2.經緯度轉中文地址(出處:Google Geocoding API),使用限制在API裡有講
Sample Code:
using System;
using System.Net;
using System.Runtime.Serialization.Json;
using System.IO;
using System.Runtime.Serialization;
using System.Text;
using System.Linq;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System.Collections.Generic;
namespace CSASPNETIPtoLocation
{
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
double lat = Convert.ToDouble("25.0392");//緯度
double lng = Convert.ToDouble("121.525");//經度
string result = latLngToChineseAddress(lat, lng);
Response.Write(result);
}
/// <summary>
/// 經緯度取得行政區
/// </summary>
/// <returns></returns>
public static string latLngToChineseDistrict(params double[] latLng)
{
string result = string.Empty;//要回傳的字串
string url =
"http://maps.googleapis.com/maps/api/geocode/json?latlng=" + string.Join(",", latLng) + "&sensor=true";
string json = String.Empty;
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
//指定語言,否則Google預設回傳英文
request.Headers.Add("Accept-Language", "zh-tw");
using (var response = request.GetResponse())
{
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
json = sr.ReadToEnd();
}
}
GoogleGeocodingAPI.RootObject rootObj = JsonConvert.DeserializeObject<GoogleGeocodingAPI.RootObject>(json);
result = rootObj.results[0].address_components
.Where(c => c.types[0] == "locality" && c.types[1] == "political").FirstOrDefault().long_name;
return result;
}
/// <summary>
/// 經緯度轉中文地址:https://developers.google.com/maps/documentation/geocoding/?hl=zh-TW#ReverseGeocoding
/// </summary>
/// <param name="latLng"></param>
public static string latLngToChineseAddress(params double[] latLng)
{
string url =
"http://maps.googleapis.com/maps/api/geocode/json?latlng=" + string.Join(",", latLng) + "&sensor=true";
string json = String.Empty;
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
//指定語言,否則Google預設回傳英文
request.Headers.Add("Accept-Language", "zh-tw");
using (var response = request.GetResponse())
{
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
json = sr.ReadToEnd();
}
}
GoogleGeocodingAPI.RootObject rootObj = JsonConvert.DeserializeObject<GoogleGeocodingAPI.RootObject>(json);
return rootObj.results[0].formatted_address;
}
}
}
namespace GoogleGeocodingAPI
{
public class AddressComponent
{
public string long_name { get; set; }
public string short_name { get; set; }
public List<string> types { get; set; }
}
public class Location
{
public double lat { get; set; }
public double lng { get; set; }
}
public class Northeast
{
public double lat { get; set; }
public double lng { get; set; }
}
public class Southwest
{
public double lat { get; set; }
public double lng { get; set; }
}
public class Viewport
{
public Northeast northeast { get; set; }
public Southwest southwest { get; set; }
}
public class Geometry
{
public Location location { get; set; }
public string location_type { get; set; }
public Viewport viewport { get; set; }
}
public class Result
{
public List<AddressComponent> address_components { get; set; }
public string formatted_address { get; set; }
public Geometry geometry { get; set; }
public bool partial_match { get; set; }
public List<string> types { get; set; }
}
public class RootObject
{
public List<Result> results { get; set; }
public string status { get; set; }
}
}
執行結果:
中文地址轉成經緯度
出處:Google Geocoding API, 使用限制在API裡
先自訂一個GoogleAPIUtilities.cs類別
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
namespace Console_ConvertShopAddrTo_latlng.Utilities
{
public class GoogleAPIUtilities
{
/// <summary>
/// 把地址轉成Json格式,這樣回傳字串裡才有緯經度
/// 因為使用到Geocoding API地理編碼技術,請注意使用限制:https://developers.google.com/maps/documentation/geocoding/?hl=zh-tw#Limits
/// </summary>
/// <param name="address">地址全名(含縣市)</param>
/// <returns></returns>
public static string ConvertAddressToJsonString(string address)
{
//申請API Key,能夠呼叫的額度會多一些
string GoogleAPIKey = ConfigurationManager.AppSettings["GoogleAPIKey"];
string url = "https://maps.googleapis.com/maps/api/geocode/json?address=" + HttpUtility.UrlEncode(address, Encoding.UTF8) + "&key=" + GoogleAPIKey;
string result = "";//回傳結果
using (WebClient client = new WebClient())
{
//指定語言,否則Google預設回傳英文
client.Headers[HttpRequestHeader.AcceptLanguage] = "zh-TW";
//不設定的話,會回傳中文亂碼
client.Encoding = Encoding.UTF8;
#region POST method才會用到
/*
client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
byte[] response = client.UploadValues("https://maps.googleapis.com/maps/api/geocode/json", new NameValueCollection()
{
{ "address", HttpUtility.UrlEncode(address, Encoding.UTF8)},
{ "key", GoogleAPIKey }
});
result = Encoding.UTF8.GetString(response);
*/
#endregion
result = client.DownloadString(url);
}//end using
return result;
}//end method
/// <summary>
/// 傳入Geocoding API產生的Json字串,取得經緯度
/// </summary>
/// <param name="json"></param>
/// <returns></returns>
public static double[] 傳入GeocodingAPI產生的Json字串取得經緯度(string json)
{
//將Json字串轉成物件
GoogleGeocodingAPI.RootObject rootObj = JsonConvert.DeserializeObject<GoogleGeocodingAPI.RootObject>(json);
//回傳結果
double[] latLng = new double[2];
//防呆
if (rootObj.status=="OK")
{
//從results開始往下找
double lat = rootObj.results[0].geometry.location.lat;//緯度
double lng = rootObj.results[0].geometry.location.lng;//經度
//緯度
latLng[0] = lat;
//經度
latLng[1] = lng;
}//end if
else
{//todo寫Log
}//end else
return latLng;
}//end method
}
}
/// <summary>
/// Json Parse資料用
/// </summary>
namespace GoogleGeocodingAPI
{
public class AddressComponent
{
public string long_name { get; set; }
public string short_name { get; set; }
public List<string> types { get; set; }
}
public class Location
{
public double lat { get; set; }
public double lng { get; set; }
}
public class Northeast
{
public double lat { get; set; }
public double lng { get; set; }
}
public class Southwest
{
public double lat { get; set; }
public double lng { get; set; }
}
public class Viewport
{
public Northeast northeast { get; set; }
public Southwest southwest { get; set; }
}
public class Geometry
{
public Location location { get; set; }
public string location_type { get; set; }
public Viewport viewport { get; set; }
}
public class Result
{
public List<AddressComponent> address_components { get; set; }
public string formatted_address { get; set; }
public Geometry geometry { get; set; }
public bool partial_match { get; set; }
public List<string> types { get; set; }
}
public class RootObject
{
public List<Result> results { get; set; }
public string status { get; set; }
}
}
在Console專案中的使用方式↓
using Console_ConvertShopAddrTo_latlng.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string address = "台北市大安區信義路4段88號";
//取得json字串
string json = GoogleAPIUtilities.ConvertAddressToJsonString(address);
Console.WriteLine(json);
//取得緯度、經度
double[] latLng = GoogleAPIUtilities.傳入GeocodingAPI產生的Json字串取得經緯度(json);
Console.WriteLine($"緯度:{latLng[0]},經度:{latLng[1]}");
}
}
}
以上的功能
由於目前找到的方法 IP直接轉地址只能得到英文結果
如果要中文的話
就照 IP→經緯度→地址 的順序使用Google API的話,就可以得到中文地址
不過要注意因為用IP來偵測使用者位置只能粗略得到經緯度,所以即時由IP得到的地址,也只是粗估,大概到縣市為止還正確之後的道路幾號門牌就不太準了