Geo-Google
view release on metacpan or search on metacpan
lib/Geo/Google.pm view on Meta::CPAN
. "Geo::Google::Location"
. " object, or subclass thereof");
return undef;
}
}
# construct the google search text
my $googlesearch = "from: " . join(', ', $locations[0]->lines);
for (my $i=1; $i<=$#locations; $i++){
$googlesearch .= " to:" . join(', ', $locations[$i]->lines);
}
my $page = get( sprintf( LQ, uri_escape( $googlesearch ) ) );
# See if google returned no results
if ( $page =~ /did\snot\smatch\sany\slocations/i ) {
$self->error( "Google couldn't find one of the locations you provided for your directions query") and return undef;
}
# See if google didn't recognize an input, but suggested
# a correction to the input that it does recognize
elsif ( $page =~ m#didyou#s )
{
# Parse the JSON to unescape the escaped unicode characters in the URLs we need to parse
my ( $strJSON ) = $page =~ m#loadVPage\((.+), "\w+"\);}//]]>#s;
my $suggestion_json = $json->jsonToObj($strJSON);
# Did you mean:</span><div class="ref"><a href="/maps?v=1&ie=UTF8&hl=en&ct=clnk&cd=1&saddr=695+Charles+E+Young+Dr+S,+Los+Angeles,+Los+Angeles,+California+90024,+United+States&daddr=10948+Weyburn+Ave,+Los+Angeles,+CA+90024+...
my ( $first_suggestion ) = $suggestion_json->{panel} =~ m#(saddr=.+?)" onclick#s;
# Get the directions using google's first suggestion
$page = get ( _html_unescape("http://maps.google.com/maps?output=js&$1") );
# warn the user using the error method, but don't return undef.
$self->error("Google suggested a different address for your query. Using the google suggestion instead.");
}
# attept to locate the JSON formatted data block
if ($page =~ m#loadVPage\((.+), "\w+"\);}//]]>#s) {
# Extract the JSON data structure from the response.
$response_json = $json->jsonToObj( $1 );
}
else {
$self->error( "Unable to locate the JSON format data in Google's response.") and return undef;
}
my @points;
my @enc_points;
for (my $i = 0; $i<=$#{$response_json->{"overlays"}->{"polylines"}}; $i++) {
$enc_points[$i] = $response_json->{"overlays"}->{"polylines"}->[$i]->{"points"};
$points[$i] = [ _decode($enc_points[$i]) ];
}
# extract a series of directions from HTML inside the panel
# portion of the JSON data response, stuffing them in @html_segs
my @html_segs;
my $stepsfound = 0;
my $panel = $response_json->{'panel'};
$panel =~ s/ / /g;
my @subpaths = $panel =~ m#(<table class="(ddrsteps(?: pw)?|ddwpt_table|dirsegment)".+?</table>\s*</div>)#gs; #ddspt_table
#my ( $subpanel ) = $response_json->{'panel'} =~ m#<table class="ddrsteps pw">(.+)</table>#s;
foreach my $subpath ( @subpaths ) {
my @segments = split m#</tr>\s*<tr#s, $subpath;
foreach my $segment ( @segments ) {
#skip irrelevant waypoint rows
if ( $subpath =~ m#ddwpt_table#s && $segment !~ m#ddptlnk#s ) { next }
my ( $id, $pointIndex ) = $segment =~ m#id="(.+?)" polypoint="(.+?)"#s;
my ( $html ) = $segment =~ m#"dirsegtext_\d+_\d+">(.+?)</td>#s;
my ( $distance ) = $segment =~ m#"sxdist".+?>(.+?)<#s;
my ( $time ) = $segment =~ m#"segtime nw pw">(.+?)<#s;
if ( ! defined( $id ) ) {
if ( $subpath =~ m#waypoint="(.+?)"#s ) {
$id = "waypoint_$1";
$html = $locations[$1]->title();
($pointIndex) = $segment =~ m#polypoint="(.+?)"#s;
}
}
next unless $id;
if ( ! $time ) {
#some segments are different (why? what is the pattern?)
my ( $d2, $t2 ) = $segment =~ m#timedist ul.+?>(.+?)\(about&\#160;(.+?)\)</td>#s;
$time = $t2;
$distance ||= $d2;
}
#some segments have no associated point, e.g. when there are long-distance driving segments
#some segments have time xor distance (not both)
$distance ||= ''; $distance = decode_entities( $distance ); $distance =~ s/\s+/ /g;
$time ||= ''; $time = decode_entities( $time ); $time =~ s/\s+/ /g;
push (@html_segs, {
distance => $distance,
time => $time,
pointIndex => $pointIndex,
id => $id,
html => $html
});
$stepsfound++;
}
}
if ($stepsfound == 0) {
$self->error("Found the HTML directions from the JSON "
. "reponse, but was not able to extract "
. "the driving directions from the HTML") and return undef;
}
my @segments = ();
# Problem: When you create a Geo::Google::Location by
# looking it up on Google from an address, it returns coordinates
# with millionth of a degree precision. Coordinates that come out
# the polyline string only have hundred thousandth of a degree
# precision. This means that the correlation algorithm won't find
# the start, stop or waypoints in the polyline unless we round
# start, stop and waypoint coordinates to the hundred-thousandth
# degree precision.
foreach my $location (@locations) {
$location->{'latitude'} = sprintf("%3.5f", $location->{'latitude'} );
$location->{'longitude'} = sprintf("%3.5f", $location->{'longitude'} );
( run in 1.271 second using v1.01-cache-2.11-cpan-71847e10f99 )