最近在做一個互連網項目,不可避免和其他互連網項目一樣,需要各種類似的功能。其中一個就是通過使用者訪問網站的IP地址顯示目前使用者所在地。在沒有查閱資料之前,我第一個想到的是應該有這樣的RESTFUL服務,可能會有免費的,也有可能會是收費的。後來查閱了相關資料和諮詢了客服人員發現了一款相當不錯的庫:GEOIP。
中文官網:http://www.maxmind.com/zh/home?pkit_lang=zh
英文官網:http://www.maxmind.com/en/home
而且GeoIP也提供了如我之前猜測的功能:Web Services,具體可以看這裡:http://dev.maxmind.com/geoip/legacy/web-services
這裡我就把官方的執行個體搬過來吧,Web Services :
首先來個Java 版本:
import java.net.MalformedURLException;import java.net.URL;import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.IOException;public class OmniReader { public static void main(String[] args) throws Exception { String license_key = "YOUR_LICENSE_KEY"; String ip_address = "24.24.24.24"; String url_str = "http://geoip.maxmind.com/e?l=" + license_key + "&i=" + ip_address; URL url = new URL(url_str); BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream())); String inLine; while ((inLine = in.readLine()) != null) { // Alternatively use a CSV parser here. Pattern p = Pattern.compile("\"([^\"]*)\"|(?<=,|^)([^,]*)(?:,|$)"); Matcher m = p.matcher(inLine); ArrayList fields = new ArrayList(); String f; while (m.find()) { f = m.group(1); if (f!=null) { fields.add(f); } else { fields.add(m.group(2)); } } String countrycode = fields.get(0); String countryname = fields.get(1); String regioncode = fields.get(2); String regionname = fields.get(3); String city = fields.get(4); String lat = fields.get(5); String lon = fields.get(6); String metrocode = fields.get(7); String areacode = fields.get(8); String timezone = fields.get(9); String continent = fields.get(10); String postalcode = fields.get(11); String isp = fields.get(12); String org = fields.get(13); String domain = fields.get(14); String asnum = fields.get(15); String netspeed = fields.get(16); String usertype = fields.get(17); String accuracyradius = fields.get(18); String countryconf = fields.get(19); String cityconf = fields.get(20); String regionconf = fields.get(21); String postalconf = fields.get(22); String error = fields.get(23); } in.close(); }}
C#版本:
private string GetMaxMindOmniData(string IP) { System.Uri objUrl = new System.Uri("http://geoip.maxmind.com/e?l=YOUR_LICENSE_KEY&i=" + IP); System.Net.WebRequest objWebReq; System.Net.WebResponse objResp; System.IO.StreamReader sReader; string strReturn = string.Empty; try { objWebReq = System.Net.WebRequest.Create(objUrl); objResp = objWebReq.GetResponse(); sReader = new System.IO.StreamReader(objResp.GetResponseStream()); strReturn = sReader.ReadToEnd(); sReader.Close(); objResp.Close(); } catch (Exception ex) { } finally { objWebReq = null; } return strReturn;}
Ruby版本:
#!/usr/bin/env rubyrequire 'csv'require 'net/http'require 'open-uri'require 'optparse'require 'uri'fields = [:country_code, :country_name, :region_code, :region_name, :city_name, :latitude, :longitude, :metro_code, :area_code, :time_zone, :continent_code, :postal_code, :isp_name, :organization_name, :domain, :as_number, :netspeed, :user_type, :accuracy_radius, :country_confidence, :city_confidence, :region_confidence, :postal_confidence, :error]options = { :license => "YOUR_LICENSE_KEY", :ip => "24.24.24.24" }OptionParser.new { |opts| opts.banner = "Usage: omni-geoip-ws.rb [options]" opts.on("-l", "--license LICENSE", "MaxMind license key") do |l| options[:license] = l end opts.on("-i", "--ip IPADDRESS", "IP address to look up") do |i| options[:ip] = i end}.parse!uri = URI::HTTP.build(:scheme => 'http', :host => 'geoip.maxmind.com', :path => '/e', :query => URI.encode_www_form(:l => options[:license], :i => options[:ip]))response = Net::HTTP.get_response(uri)unless response.is_a?(Net::HTTPSuccess) abort "Request failed with status #{response.code}"endomni = Hash[fields.zip(response.body.encode('utf-8', 'iso-8859-1').parse_csv)]if omni[:error] abort "MaxMind returned an error code for the request: #{omni[:error]}"else puts puts "MaxMind Omni data for #{options[:ip]}"; puts omni.each { |key, val| printf " %-20s %s\n", key, val } putsend
最後再來個Perl版本吧:
#!/usr/bin/env perluse strict;use warnings;use Encode qw( decode );use Getopt::Long;use LWP::UserAgent;use Text::CSV_XS;use URI;use URI::QueryParam;my @fields = qw( country_code country_name region_code region_name city_name latitude longitude metro_code area_code time_zone continent_code postal_code isp_name organization_name domain as_number netspeed user_type accuracy_radius country_confidence city_confidence region_confidence postal_confidence error);my $license_key = 'YOUR_LICENSE_KEY';my $ip_address = '24.24.24.24';GetOptions( 'license:s' => \$license_key, 'ip:s' => \$ip_address,);my $uri = URI->new('http://geoip.maxmind.com/e');$uri->query_param( l => $license_key );$uri->query_param( i => $ip_address );my $ua = LWP::UserAgent->new( timeout => 5 );my $response = $ua->get($uri);die 'Request failed with status ' . $response->code() unless $response->is_success();my $csv = Text::CSV_XS->new( { binary => 1 } );$csv->parse( decode( 'ISO-8859-1', $response->content() ) );my %omni;@omni{@fields} = $csv->fields();binmode STDOUT, ':encoding(UTF-8)';if ( defined $omni{error} && length $omni{error} ) { die "MaxMind returned an error code for the request: $omni{error}\n";}else { print "\nMaxMind Omni data for $ip_address\n\n"; for my $field (@fields) { print sprintf( " %-20s %s\n", $field, $omni{$field} ); } print "\n";}
以上都是基於Web Services的,這裡我再寫個使用本地庫的執行個體,而項目中也使用的是本地庫。
首先在項目中需要添加庫檔案:GeoLiteCity,然後就可以利用這個檔案得到城市和國家資訊了。項目中如何擷取到使用者訪問的IP地址就不用我說了吧,做過Web開發的人應該都知道。Request裡面擷取。Java代碼:
public class GeoBusiness {/** * @param args * @throws IOException */public static void main(String[] args) throws IOException {// TODO Auto-generated method stubSystem.out.println(getLocationByIp("220.181.111.147").getCity());System.out.println(getLocationByIp("220.181.111.147").getCountryName());}public static Location getLocationByIp(String ipaddr) throws IOException {String sep = System.getProperty("file.separator");String dir = Play.configuration.getProperty("geoip.datdir");String dbfile = dir + sep + "GeoLiteCity.dat";LookupService cl = new LookupService(dbfile,LookupService.GEOIP_MEMORY_CACHE);Location location = cl.getLocation(ipaddr);cl.close();return location;}}
更詳細的功能比如擷取省,經緯度可以參考我最前面給出的網址。