1 package Geo::USCensus::Geocoding;
7 use HTTP::Request::Common;
8 use Geo::USCensus::Geocoding::Result;
13 Geo::USCensus::Geocoding - The U.S. Census Bureau geocoding service
17 our $VERSION = '0.02';
22 use Geo::USCensus::Geocoding;
26 street => '123 Main Street',
27 city => 'San Francisco', # city
28 state => 'CA', # state
30 zip => '93102', # zip code
31 benchmark => 'Public_AR_ACS2013', # default is "Public_AR_Current"
32 vintage => 'Census2010_ACS2013', # default is "Current_Current"
34 debug => 1, # will print the URL and some other info
36 my $result = Geo::USCensus::Geocoding->query($request);
38 if ($result->is_match) {
39 print $result->address,"\n",
40 $result->latitude,", ",$result->longitude,"\n",
41 $result->censustract,"\n";
50 Send a request to the web service. See
51 L<http://geocoding.geo.census.gov/geocoder> for API documentation. This
52 package will always use the batch method (which seems to be more reliable,
53 as of 2015) and the Geographies return type.
55 Returns an object of class Geo::USCensus::Geocoding::Result.
59 my $ua = LWP::UserAgent->new;
60 my $url = 'https://geocoding.geo.census.gov/geocoder/geographies/addressbatch';
62 my $csv = Text::CSV->new({eol => "\n", binary => 1});
64 # for a current list of benchmark/vintage IDs, download
65 # http://geocoding.geo.census.gov/geocoder/benchmarks
66 # http://geocoding.geo.census.gov/geocoder/vintages?benchmark=<id>
67 # with Accept: application/json
72 returntype => 'geographies',
73 benchmark => 4, # "Current"
74 vintage => 4, # "Current"
76 if (ref $_[0] eq 'HASH') {
77 %opt = (%opt, %{ $_[0] });
82 $DEBUG = $opt{debug} || 0;
84 my $result = Geo::USCensus::Geocoding::Result->new;
86 my @row = ( 1 ); # first element = row identifier
87 # at some point support multiple rows in a single query?
89 $result->error_message("Street address is required.");
92 if (!$opt{zip} and (!$opt{city} or !$opt{state})) {
93 $result->error_message("Either city/state or zip code is required.");
96 foreach (qw(street city state zip)) {
97 push @row, $opt{$_} || '';
101 warn "Sending:\n".$csv->string."\n" if $DEBUG;
103 # they are not picky about content types, Accept headers, etc., but
104 # the uploaded file must have a _name_.
105 my $resp = $ua->request(POST $url,
106 'Content_Type' => 'form-data',
107 'Content' => [ benchmark => $opt{benchmark},
108 vintage => $opt{vintage},
109 returntype => $opt{returntype},
110 addressFile => [ undef, 'upload.csv',
111 Content => $csv->string
115 if ( $resp->is_success ) {
116 $result->content($resp->content);
117 my $status = $csv->parse($resp->content);
118 my @fields = $csv->fields;
119 if (!$status or @fields < 3) {
120 $result->error_message("Unable to parse response:\n" . $resp->content);
123 if ( $fields[2] eq 'Match' ) {
124 $result->is_match(1);
125 $result->match_level($fields[3]);
126 $result->address($fields[4]);
127 my ($long, $lat) = split(',', $fields[5]);
128 $result->longitude($long);
129 $result->latitude($lat);
130 $result->state($fields[8]);
131 $result->county($fields[9]);
132 $result->tract($fields[10]);
133 $result->block($fields[11]);
135 $result->is_match(0);
136 $result->match_level($fields[2]); # "No_Match", "Tie"
139 $result->error_message( $resp->status_line );
147 Mark Wells, C<< <mark at freeside.biz> >>
151 Commercial support for this module is available from Freeside Internet
154 L<http://www.freeside.biz/>
159 =head1 LICENSE AND COPYRIGHT
161 Copyright (C) 2014 Mark Wells.
162 Copyright (C) 2016 Freeside Internet Services, Inc.
164 This program is free software; you can redistribute it and/or modify it
165 under the terms of either: the GNU General Public License as published
166 by the Free Software Foundation; or the Artistic License.
168 See http://dev.perl.org/licenses/ for more information.