Current Temperature (#68)

An answer just for the fun of it, showing that you write as obscure and
unmaintainable code in Ruby as in Perl. The challenge was to get all the
functionality in a one liner, in order to see how far you can stretch
ruby
expressions. They seem to stretch pretty well:-)

It uses Google, so it supports only zip codes as input.

require ‘net/http’
puts ((ARGV.length != 1) ? “Usage: #$0 ” : ([“The temperature
in”] + (/Weather</b> for
(.)</b>.\D(\d+)°F/.match(Net::HTTP.get(
URI.parse(“temperature - Google Search”)))[1,2].collect!
{|x| " is " + x})).to_s.gsub!(/in is /, "in “) + " degree F”)

./temp.rb 94117
The temperature in San Francisco, CA is 57 degree F
./temp.rb
Usage: ./temp.rb

Cool. I’d tried to do something like that, but couldn’t quite get it to
work (because of the yahoo redirect). Looking at your code helped me
figure it out. I looked at net/http and then more at what open-uri
provides. Lo and behold it provides some meta-data that helps with the
redirect problem. Anyways thanks gordon! I added my now fixed function
below.

-----Jay A.

require ‘rexml/document’
require ‘open-uri’

LOC_MATCH = //forecast/([^.]+).html/

#Searches Yahoo and returns an array of location ids
def yahoo_loc_search(loc)
return [loc] if loc =~ /\d/ #places usually don’t have numbers in
their names
locs = []

open(“Santa Clara, United States - Weather Forecasts | Maps | News - Yahoo Weather”)
do |http|
return [$1] if http.base_uri.to_s =~ LOC_MATCH
http.each {|line| locs << $1 if line =~ LOC_MATCH }
end
locs
end

#Returns a hash containing the location and temperature information
#Accepts US zip codes or Yahoo location id’s
def yahoo_weather_query(loc_ids, units)
weather = []
loc_ids.each do |l|
h = {}

open(“http://xml.weather.yahoo.com/forecastrss?p=#{l}&u=#{units}”) do
|http|
response = http.read
doc = REXML::Document.new(response)
channel = doc.root.elements[‘channel’]
title = channel.elements[‘title’].text
if title !~ /Error/ then
location = channel.elements[‘yweather:location’]
h[:city] = location.attributes[“city”]
h[:region] = location.attributes[“region”]
h[:country] = location.attributes[“country”]
h[:temp] =
channel.elements[“item”].elements[“yweather:condition”].attributes[“temp”]
weather << h
end
end
end
weather
end

if ARGV.length < 1 then
puts “usage: #$0 [f|c]”
exit
end
loc_id = ARGV[0]
units = (ARGV[1] || ‘f’).downcase
units = (units =~ /^(f|c)$/) ? units : ‘f’

loc_ids = yahoo_loc_search(loc_id)
weather_info = yahoo_weather_query(loc_ids, units)

puts “No matches found” if weather_info.size == 0

weather_info.each do |w|
city = w[:city]
region = w[:region]
country = w[:country]
temp = w[:temp]

final_loc = "#{city}, #{region}#{', ' if region!="" and

country!=“”}#{country}"
puts “The temperature in #{final_loc} is #{temp} degrees
#{units.upcase}”
end

Hi all!

Is there any way one of you could modify your web scraping application
so that it functions for historical weather data? I want to be able to
enter a zip code and get the hourly weather for every day of 2015. Any
ideas? =)

Thanks!