Here is mine. It only provides temperatures for US zip codes. I've
been doing some HTML scraping like this lately for some utilities of
my own, so this was pretty easy (i.e. the techniques were fresh in my
mind.) Though for my other utilities I've been using WWW:Mechanize and
in this case I decided to go a little lower level.

One problem with this or any other HTML scraping solution, is minor
changes to the HTML can totally break things.

Beware of wrapping, especially on the "parse_list":

require 'open-uri'

if $0 == __FILE__
  if ARGV.length < 1
    puts "Usage: #$0 <zip code>"
    exit(1)
  end
  parse_list = [[/<B>Local Forecast for (.* \(\d{5}\))<\/B>/, 'Local
temperature for #$1: '],
    [/<B CLASS=obsTempTextA>([^&]*)&deg;(.)<\/B>/, '#$1 degrees #$2 '],
    [/<B CLASS=obsTextA>Feels Like<BR> ([^&]*)&deg;(.)<\/B>/, '[It
feels like #$1 degrees #$2]']
  ]
  # Blessed be the internet, the great provider of information
  open('http://beta.weather.com/weather/local/'+ARGV[0]) do |io|
    html = io.read
    parse_list.each do |p|
      # We don't need no steenkin' HTML parser
      if html =~ p[0]
        print eval(%Q{"#{p[1]}"})
      end
    end
    puts
  end
end

Ryan