http://qs321.pair.com?node_id=14511
Category: Utility / Web
Author/Contact Info scribe@ziplip.com
Description: Grabs weather from yahoo. One of my first perl scripts
and my first use of IO::Socket. It could use some work
but I only use it as part of an efnet bot.
#!/usr/bin/perl

use IO::Socket;

if ($#ARGV < 0) { die "usage: weather.pl <zipcode | city>\n"; }

$server = 'search.weather.yahoo.com';
$serverPort = '80';
$get = '/weather/query.cgi?q=';

$zipcode = $ARGV[0];

$remote = new IO::Socket::INET (
                  Proto=>'tcp',
                  PeerAddr=>$server,
                  PeerPort=>$serverPort,
                  Reuse=>1 ) or die $!;

$remote -> autoflush(1);

print $remote "GET $get"."$zipcode HTTP/1.0\n\n";

while ( $location = <$remote>) {
  if ( $location =~ /Location:/ ) {
    $redir = $location;
    $redir =~ s/Location: //;
  }
}

close $remote;

if ($redir eq '') {
  print "Sorry, unable to gather weather data for $zipcode\n";
  exit;
}

@temp = split(/\//, $redir);
$server = $temp[2];
$get = "\/"."$temp[3]"."\/"."$temp[4]";

$remote = new IO::Socket::INET (
                  Proto=>'tcp',
                  PeerAddr=>$server,
                  PeerPort=>$serverPort,
                  Reuse=>1 ) or die $!;

$remote -> autoflush(1);

print $remote "GET $get HTTP/1.0\n\n";

while ( $raw = <$remote>) {

  if ($raw =~ /Appar Temp:/) {
    $temp = $raw;
  } elsif ($raw =~ /Humidity:/) {
    $humidity = $raw;
  } elsif ($raw =~ /Wind:/) {
    $wind = $raw;
  } elsif (($raw =~ /^<font size=\"-2\" face=\"arial\">.+<\/font><\/td
+>$/) && ($condFound ne 1)) {
    $conditions = $raw;
    $condFound = 1;
  } elsif ($raw =~ / Forecast<\/title>/) {
    $city = $raw;
  }

}

close $remote;

$conditions =~ s/^<font size=\"-2\" face=\"arial\">//;
$conditions =~ s/<\/font><\/td>$//;
chomp $conditions;

$temp =~ s/<tr><td><font size=-1>//;
$temp =~ s/<\/font><\/td>//g;
$temp =~ s/<td><font size=-1>//;
$temp =~ s/<\/tr>//;
$temp =~ s/:/: /;
$temp =~ s/Appar //;
$temp =~ s/&#176\;/ degrees/;
chomp $temp;

$humidity =~ s/<tr><td><font size=-1>//;
$humidity =~ s/<\/font><\/td>//g;
$humidity =~ s/<td><font size=-1>//;
$humidity =~ s/<\/tr>//;
$humidity =~ s/:/: /;
$humidity =~ s/% /%/;
chomp $humidity;

$wind =~ s/<tr><td><font size=-1>//;
$wind =~ s/<\/font><\/td>//g;
$wind =~ s/<td><font size=-1>//;
$wind =~ s/<\/tr>//;
$wind =~ s/&nbsp\;/ /;
$wind =~ s/:/: /;
chomp $wind;

$city =~ s/<title>//;
$city =~ s/<\/title>//;
$city =~ s/Weather Forecast//;
chomp $city;

print "Weather for $city(( $temp $humidity ) ( $conditions $wind ))\n"
+;
Replies are listed 'Best First'.
RE: OPPS - Grab weather from yahoo (2)
by KM (Priest) on May 24, 2000 at 21:01 UTC
      I used one of the CPAN weather grabbers with mixed results.

      Often the ports would time out when I used the module as written.

      My solution was to dupe the .pm and localize it to pull only from the Los Angeles NOAA station instead of the central/national one. This one had a lot less traffic, and I haven't seen any lost results since I made the switch.

      In case anyone is interested, I modified Geo::WeatherNOAA as Geo::LAWeatherNOAA.
      In the subroutine get_city_zone I changed my $URL = $URL_BASE . lc $state . '/zone.html'; to my $URL = 'http://www.nwsla.noaa.gov/zones/LAXZFPLOX'; and that took care of just about everything.

RE: OPPS - Grab weather from yahoo (2)
by Adam (Vicar) on May 24, 2000 at 20:55 UTC
    This worked really well the first time. Then I ran it again with a different zip code and it crashed thusly:
    IO::Socket::INET: Bad peer address at D:\FileBin\weather.pl line 36
    Bad file descriptor at D:\FileBin\weather.pl line 36.
    
    Line 36 is this one:$remote = new IO::Socket::INET ((I think)
      I believe this is caused when yahoo splits that
      zipcode / city up into differnt weather reports or
      the city is found in multiple states.

      On yahoo's site it lists options of differnt locations
      in such instances and the users is expected to drill down
      by clicking one of the links.

      I've added an if statement to make it quit nicely.
      Maybe I'll reqrite it using one of the modules KM has
      pointed out.

      -scribe