google map apiによるgeocoding概要
http://code.google.com/intl/ja_ALL/apis/maps/documentation/services.html#Geocoding
google map api を使用すれば、geocoding、すなわち、住所→座標(緯度 経度)を行うことができます。例えば、次のようなグーグル株式会社のgeocodingをxmlで取得するには次のように行います。
http://maps.google.co.jp/maps/geo?key=&output=xml&q=東京都渋谷区桜丘町26-1
※実際にはkey(ApiKey)も指定して下さい。
google map apiのレスポンスには、statusコードもある為、指定住所の取得失敗等も判断することができます。
http://code.google.com/intl/ja/apis/maps/documentation/reference.html
http://maps.google.co.jp/maps/geo?key=&output=xml&q=ありえない住所
この他にstatus=200であるにも関わらず、複数の候補が得られる場合もあります。
http://maps.google.co.jp/maps/geo?key=&output=xml&q=久留米
google map apiでgeocodingできない分をゼンリン地図でフォロー
ただし、実際にある住所にもかかわらず、google map apiでgeocodingできない場合がいくつかあるようです。
最近では、いろいろ地図サービスがありますが、変換精度や使い勝手の点でゼンリン地図がよさそうだったので、google map apiでgeocodingできない分は、ゼンリン地図でフォローすることにしました。
ゼンリン地図の場合、apiを公開しているわけではない為、出力されるhtmlをparseする必要がありますが、次のように行えば、google map api & ゼンリン地図によるgeocodingを実現することができます。
#!/usr/local/bin/perl use strict; use warnings; use Encode; use Encode::Guess qw/shift-jis euc-jp utf-8/; use LWP::UserAgent; use XML::Simple; use Data::Dumper; #http://maps.google.co.jp/maps/geo?key=&output=xml&q=東京都渋谷区桜丘町26-1 my $GMAP_API = "http://maps.google.co.jp/maps/geo?output=xml"; my $GMAP_KEY = ""; #http://free.its-mo.com/?freewd=東京都渋谷区桜丘町26-1 my $ZENRIN_API = "http://free.its-mo.com/"; my @ZENRIN_GEO_RET; sub main { my ($address_file) = @_; open my $fh, $address_file or die "can't open file:$address_file:$!"; my @adrs_lines = <$fh>; close($fh) or die "can't open file:$address_file:$!"; for my $line ( @adrs_lines ){ $line =~ s/\s+$//o; $line = decode("shift-jis", $line); $line = encode("utf-8", $line); #「名前<tab>住所org」の形式 my @cols = split("\t",$line); #sys : 「gmap api」 or 「zenrin」 #adrs_new : geocoderによるparse済住所 #coord : 世界測地系d形式の緯度経度 my ($sys,$adrs_new,$coord) = geocode( $cols[1] ); $sys ||= ""; $adrs_new ||= ""; $coord ||= ""; print "$cols[0]\t$cols[1]\t$sys\t$adrs_new\t$coord\n"; sleep(1); } } sub geocode { my ($adrs_org) = @_; my $ua = LWP::UserAgent->new(); my $xml = XML::Simple->new(); #まずは、google map apiで「住所→緯度経度」 my $res = $ua->get("$GMAP_API&key=$GMAP_KEY&q=$adrs_org"); unless ( $res->is_success ){ print STDERR "fail http get:$adrs_org\n"; return undef; } my $xml_str = $res->content; $xml_str = decode("Guess", $xml_str); my $geo = $xml->XMLin( $xml_str ); if ( $geo->{Response}->{Status}->{code} eq "200" and defined($geo->{Response}->{Placemark}->{address}) ){ my $adrs = encode("utf-8", "$geo->{Response}->{Placemark}->{address}"); my @co = split(/,/,"$geo->{Response}->{Placemark}->{Point}->{coordinates}"); return ("google",$adrs,"$co[0] $co[1]"); } #google map apiで取得できない場合、zenrinで「住所→緯度経度」 $res = $ua->get("$ZENRIN_API?freewd=$adrs_org"); unless ( $res->is_success ){ print STDERR "fail http get:$adrs_org\n"; return undef; } my $html_str = $res->content; my $parser = HTML::Parser->new(api_version => 3, start_h =>[\&read_zenrin_html, "self, tagname, attr, text"], marked_sections => 1); $parser->parse($html_str); return ("zenrin",@ZENRIN_GEO_RET) if $ZENRIN_GEO_RET[0]; print STDERR "fail geocode: $adrs_org\n"; return undef; } sub read_zenrin_html { my ($self, $tagname, $attr, $text) = @_; return undef if ($tagname ne "input"); return undef if (not defined($attr->{name}) or $attr->{name} ne "link" ); my $val = decode("utf-8", $attr->{value}); @ZENRIN_GEO_RET = (); my ($adrs,$lat,$lon) = $val =~ /^fw:.+\,(.+):(\d+):(\d+)$/o; ($lon,$lat) = conv_co_tokyo_to_wgs84($lon,$lat); @ZENRIN_GEO_RET = ( encode("utf-8",$adrs),"$lon $lat"); return 1; } #日本測地系→世界測地系 sub conv_co_tokyo_to_wgs84 { my ($lon,$lat) =@_; $lon = $lon / 1000 / 3600; $lat = $lat / 1000 / 3600; return ($lon - $lat*0.000046038 - $lon*0.000083043 + 0.010040, $lat - $lat*0.00010695 + $lon*0.000017464 + 0.0046017); } main(@ARGV);