Previous | Table of Contents | Next |
Weather StationFor your first Perl glue feat, you're going to create your own weather application. You might be familiar with those desktop applications that run on the desktop toolbar and display the current temperature. You're going to build your own (at least, a text version) in Perl. Your requirements will be the following:
Not too difficult, eh? Now you have to construct how you're going to get from the ZIP code to a weather report:
So reversing your steps gives you the procedure you need to write your program:
Let's do this program in three different parts. Of course, it should all be combined at the end into one large program. Part 1: Finding Out Where You AreThe first part of your problem is going from a ZIP code to a latitude and longitude. The U.S. Census Bureau maintains the U.S. Gazetteer Place and ZIP code database. To query the database, go to http://www.census.gov/cgi-bin/gazetteer and enter a ZIP Code. If I use 48220, the resulting web page is shown in Figure 20.1. Figure 20.1. US Census Bureau's Gazetteer web interface.The first thing to notice is the URL in the browser's Address window. Notice how the ZIP code 48220 stands out in the URL? If you were to type in the URL http://www.census.gov/cgi-bin/gazetteer?city=&state=&zip=90210 the web site returns information on Beverly Hills, CA. The module XML::Simple has a function called get that works like this: my $page = get("http://www.census.gov/cgi-bin/gazetteer?city=&state=&zip=48220"); The web page will be fetched and stored in the variable $page. What's $page going to look like? It will contain the HTML source for the web page. If you right-click in your browser and select View Source you can look at the source. It will look something like Figure 20.2. Figure 20.2. HTML output from a Gazetteer query.Because it's just text in $page, you can use regular expressions to get the Location information you need. Listing 20.1 will retrieve a prompt for a ZIP code, retrieve the page, and get the location information. Listing 20.1. Retrieving the ZIP Information1: #!/usr/bin/perl -w 2: 3: # Part 1 Retrieve the Latitude & Longitude based on the ZIP Code 4: # Also, retrieve the modules you need for this Exercise 5: use strict; 6: use LWP::Simple; 7: use XML::Simple; 8: use Math::Trig; 9: 10: print "Weather for what ZIP code?"; 11: my $zip = <>; 12: chomp $zip; 13: 14: my $zipdata = get("http://www.census.gov/cgibin/gazetteer?city=&state=&zip=$zip"); 15: 16: if ($zipdata =~ /no matches found/) { 17: die "Invalid zip code"; 18: } 19: 20: my ($ziplat, $ziplon) = $zipdata=~/Location: (\d+\.\d+) N, (\d+\.\d+) W/; 21: my ($poName) = $zipdata=~ /PO Name: ([^<]+)/;
You now have the ZIP code's rough latitude and longitude information. Part 2: Finding the Local AirportNow that you know where the ZIP code is, you need to find the local airport. At the URL http://www.nws.noaa.gov/data/current_obs/index.xml there is an XML document that lists the NOAA observation stations and the latitude and longitude of each. A sample of the document is shown in Figure 20.3. Figure 20.3. A Bit of the NOAA XML file showing the data structure.This is a large file (more than 700KB), it doesn't change often, and you don't want to retrieve it every time you do a weather lookup. It should be saved to a file, and then the file should be referenced when a lookup is necessary. This example assumes it's stored in a file called stations.xml. To find the closest airport, you're going to use this formula: distance = 3963.1 * arccos( sin(Lat1) * sin(Lat2) + cos(Lat1) * cos (Lat2) * cos(Lon1-Lon2))) This formula computes, in miles, the distance on the surface of the earth between two points given their latitude and longitude (expressed in radians). If you apply this formula to every airport in the list and your ZIP code's latitude and longitude, and remember which airport is closest, you should get the most relevant METAR code. The code in Listing 20.2 takes the latitude and longitude gathered from Gazetteer and computes the distance to each airport listed in the NOAA database. The closest airport (METAR station) is recorded for later use in Part 3. Listing 20.2. Finding the Nearest Airport22: 23: # Part 2 Using the Latitude and Longitude 24: # find the closest METAR station 25: my $metar = XMLin("./stations.xml"); 26: my $bestDistance = 10000; 27: my $closestStation = undef; 28: my $rad = 57.29577951; 29: 30: my ($latmin, $lonmin); 31: foreach my $station ( @ { $metar->{station} } ) { 32: my ($lat, $lon) = ($station->{latitude}, $station->{longitude}); 33: next if ($lat eq "NA"); 34: ($lat, $latmin) = $lat=~/(\d+)\.(\d+)/; 35: ($lon, $lonmin) = $lon=~/(\d+)\.(\d+)/; 36: $lat = (int($lat) + $latmin/60)/$rad; 37: $lon = (int($lon) + $lonmin/60)/$rad; 38: 39: my $greatcircle = 3963.1 * acos( 40: sin($ziplat/$rad)*sin($lat) + 41: cos($ziplat/$rad)*cos($lat) * 42: cos(abs($ziplon/$rad - $lon)) 43: ); 44: 45: if ($bestDistance > $greatcircle) { 46: $bestDistance = $greatcircle; 47: $closestStation = $station; 48: } 49: }
|
Previous | Table of Contents | Next |