mcoblentz has asked for the wisdom of the Perl Monks concerning the following question:

Update 23 July:

Well, this is getting a bit more interesting. The API call from Google is returning a status of "ZERO RESULTS". So my question now is a bit more fun - and wanders off into the area of hashes/arrays, which I'm not all that good at.

The API returns a status in its XML response that looks like this:

The XML returned by this request is shown below. <GeocodeResponse> <status>OK</status> <result> <type>street_address</type> <formatted_address>1600 Amphitheatre Pkwy, Mountain View, CA 94043, +USA</formatted_address>

The API call Geocode queries $location to Google Maps geocoding API and returns hash reference returned back from API server.

how can I read the hash reference for the status? My intent would be to write the necessary IF statements to handle the program flow from there but I am not certain how to grab the status out of the returned information.

Suggestions?

Brothers and Sisters,

I'm pretty sure I have made a rookie mistake somewhere but the obvious is eluding me. I have a script which is not throwing any errors and should be. (Sounds like a nice problem to have!) The script scrapes job listings from the web and outputs a geocode for them. (The idea is to plot them on a world map so we just need the lat/long). Anyway, some of the job postings are not completely well formed and Google sometimes throws an error - zero results. I tried to trap that and planned to put in a dialog but now my error routine is skipping the offending locations.

If you try the script, you'll see that jobs #6 and #7 are not processed. I'm trying to trap those so I can get a realistic geocoding, but my error routine is just skipping it.

What have I done wrong?

****** START ****** START ****** START ****** START ****** START **** +** START job no.: 1 Senior Implementation Specialist ==> Prof Svcs Boulogne-Bi +llancourt, , France 48.8396952 2.2399123 job no.: 2 Marketing Manager ==> Marketing Vienna, Wien, Austria 48. +2081743 16.3738189 job no.: 3 Solutions Architect - Consulting Architecture ==> Prof Svc +s Boulogne-Billancourt, , France 48.8396952 2.2399123 job no.: 4 Lead Generation Specialist ==> Marketing Oceanport, New Je +rsey, United States 40.3181663 -74.0151382 job no.: 5 Facilities Supervisor ==> IT Oceanport, New Jersey, United + States 40.3181663 -74.0151382 job no.: 8 Director, Channel Sales ==> Partners PO Box 502224, , Unit +ed Arab Emirates 23.424076 53.847818

My script is here and the offending logic is where the eval block begins... at least, I think that's where the problem is.

This is the input that I was expecting my code to trap Google's complaint:

306926-636 Enterprise Account Manager Remote, , Turkey 7/5/20 +14 306927-636 Solutions Architect - Consulting Architecture Remote, + , Israel 7/5/2014

Snippet:

# having assigned the job title to a category, now try to lookup the # lat and long of the job position so we can plot in on a map. # turns out the Google API has a limit of 10 geocodes per second s +o we # need a loop to throttle the request rate. otherwise google thro +ws an error # and I am not sure how to trap it. if ($loop < 10) { $geocoder = Geo::Coder::Google->new(apiver => 3); eval{ $latlong = $geocoder->geocode(location => $location); if ($1){ print "!!! !!! !!! --- Couldn't get location : $locati +on --- !!! !!! !!!\n"; }else{ $map_coords = $latlong->{geometry}{location}{lat} . " +" . $latlong->{geometry}{location}{lng}; print ( " job no.\: $job_count $job_title \=\=\> $department $ +location $map_coords \n" ); $loop++; } } } else { print ( " job no.\: $job_count $job_title \=\=\> $department $ +location $map_coords \n" ); $loop = 0; sleep 1; } # count up the jobs by category # if the category already exists in the hash table then increment +it if (exists $categories{$department} ) { $categories{$department}++; } # otherwise add it and initialize the counter to '1'. else { $categories{$department} = 1; } # count up the jobs by city # if the location already exists in the hash table then increment +it if (exists $offices{$map_coords} ) { $offices{$map_coords}++; } # otherwise add it and initialize the counter to '1'. else { $offices{$map_coords} = 1; $cities{$map_coords} = $location; } # need to loop through the offices hash and scale out the size of +the dot print ($out_fh "$map_coords \"\" color=red symbolsize=", "$offices +{$map_coords}", "\n"); print ($out_fh "$map_coords \"\" color=red symbolsize=", "$offices{$ma +p_coords}" * "2", "\n \n"); } p %categories; p %offices; p %cities; close ($out_fh);

Replies are listed 'Best First'.
Re: Trapping errors
by AppleFritter (Vicar) on Jul 10, 2014 at 17:08 UTC
    In addition to what my anonymous brother said, I'd suggest checking $@ after using eval -- when using an eval block to catch exceptions, it's a good idea to check if an exception actually occured.
      Thanks, I tried that but I didn't get a true answer from the API. Turns out its giving back a "non-OK" status but not really an error. So I need to read the hash return and grab the status. I just need a bit of help with that and I'm off!
Re: Trapping errors
by Anonymous Monk on Jul 10, 2014 at 16:52 UTC
    I'm trying to trap those so I can get a realistic geocoding, but my error routine is just skipping it.
    I'm not familiar with this module, but
    eval{ $latlong = $geocoder->geocode(location => $location);
    Apparently geocode dies here and the rest of the eval block is skipped. From the source of the module (V3):
    $param{location} = shift; ... my $location = $param{location} or Carp::croak("Usage: geocode(location => \$location)");
    Maybe try to check manually whether your $location is empty?
Re: Trapping errors
by Laurent_R (Canon) on Jul 10, 2014 at 20:30 UTC
    I am also not familiar with this module, but this does not seem to be quite right:
    if ($loop < 10) { $geocoder = Geo::Coder::Google->new(apiver => 3); eval{ $latlong = $geocoder->geocode(location => $location); if ($1){ print "!!! !!! !!! --- Couldn't get location : $locati +on --- !!! !!! !!!\n"; }else{ $map_coords = $latlong->{geometry}{location}{lat} . " +" . $latlong->{geometry}{location}{lng}; print ( " job no.\: $job_count $job_title \=\=\> $department $ +location $map_coords \n" ); $loop++; } } }
    Now the questions: 1. if ($1), $1 is a special variable used for the first successful match in a regex, but you don't seem to be using any regex. 2. Nor sure you should use an eval, it might be better to see if $latlong is defined and is a reference (I assume it should be a reference) to some data structure that is also properly defined. 3. If you really want to use eval, then you should really check the value of $@, which contains the Perl error message from the last eval (but AppleFritter++ has already mentioned this to you. In brief, you do not seem to be doing the steps needed to catch an error, I am not too surprised that you don't catch any.

    Now, of course, all the above is in part speculation, as I said, I do not know this module (and have no time right now to go through it), but I still hope it might help you.

      Ah, thank you for all that. I went through the usual error variables and ultimately found that the API call was not returning an error per se - but in the internal 'status' field it says, "ZERO RESULTS". So I need to read the status field from the returned hash and control the program flow from there. Problem is, I am not certain how to read the hash. I didn't call for one so what do I read? Any thoughts? Thanks!
        Your $geocoder variable is probably a reference to an object that most probably has accessors within its methods. Use them. If worse comes to worse, you could probably use the Data::Dumper to figure out the underlying data structure, this might help you understanding what is going on, but you should most probably not rely on that for your real program, but use the methods provided by the interface.