#!/usr/bin/env ruby require 'net/http' require 'rexml/document' ProgramName = File.basename($0) ProgramVers = "0.2" ProgramAuth = "Patrick Mueller (pmuellr@yahoo.com)" #-------------------------------------------------------------------- # sea / wave forecasts available here: # http://www.nws.noaa.gov/om/marine/zone/usamz.htm #-------------------------------------------------------------------- UrlHost = "weather.noaa.gov" UrlPath = "/cgi-bin/fmtbltn.pl?file=forecasts/marine/coastal/am" UrlPrefix = "http://#{UrlHost}#{UrlPath}" #-------------------------------------------------------------------- # locations to get the forecast for; # [0] human readable name # [1] uri of the report to fetch # [2] latitude # [3] longitude # [4] zip code (for weather) #-------------------------------------------------------------------- locationData = [ [ "Wrightsville Beach", "amz250.txt", 34.206479, -77.791357, 28480 ], [ "Emerald Isle", "amz158.txt", 34.6713, -76.98763, 28594 ], [ "Ocracoke", "amz154.txt", 35.108535, -75.942307, 27960 ], [ "Hatteras", "amz152.txt", 35.491425, -75.462685, 27943 ], [ "Outer Banks", "amz150.txt", 35.974116, -75.648937, 27948 ], ] #-------------------------------------------------------------------- # information about a location #-------------------------------------------------------------------- class Location attr_accessor :name, :uri, :lat, :long, :zip, :weather, :seas #------------------------------------------------------------------ # constructor #------------------------------------------------------------------ def initialize(name, uri, lat, long, zip) @name = name @uri = uri @long = long @lat = lat @zip = zip puts "Processing #{name}" getWeather getSeas end private #------------------------------------------------------------------ # get the weather forecast #------------------------------------------------------------------ def getWeather() puts " getting weather" xml = Net::HTTP.get("xml.weather.yahoo.com", "/forecastrss?p=#{@zip}") doc = REXML::Document.new xml root = doc.root html = root.elements['channel/item/description'].text @weather = html.gsub(%r{}mi,"") @weather = @weather.sub(%r{}mi,"") end #------------------------------------------------------------------ # get the sea info #------------------------------------------------------------------ def getSeas() puts " getting sea forecasts" html = Net::HTTP.get(UrlHost, "#{UrlPath}/#{@uri}") #------------------------------------------------------------------ # extract the juicy center #------------------------------------------------------------------ prePattern = %r{
(.*)
}m match = prePattern.match(html) if (!match) @seas = "

Unable to parse sea forecast.

" return end html = match[1] #------------------------------------------------------------------ # split the file at bolded terms; this will give us header/body/header/... #------------------------------------------------------------------ sections = html.split(%r{|}) #------------------------------------------------------------------ # remove all the initial sections until we have a known header #------------------------------------------------------------------ firstPattern = %r{} while (!firstPattern.match(sections.first)) sections.shift end #------------------------------------------------------------------ # now build the table, one row per 'day' #------------------------------------------------------------------ html = "\n\n" while (!sections.empty?) header, body, *sections = sections header.gsub!(%r{<.*?>},'') header = header.downcase.strip body = body.downcase.strip body = getWaveInfo(body) header = header.gsub(" "," ") next if header.include?("night") html += "\n" end @seas = "#{html}
#{header}  #{body}
\n" end #------------------------------------------------------------------ def getWaveInfo(text) seasPattern = %r{.*?(SEAS.*?FT).*}mi wavesPattern = %r{.*?(WAVES.*?FT).*}mi match = seasPattern.match(text) return match[1] if match match = wavesPattern.match(text) return match[1] if match return "???" end end #-------------------------------------------------------------------- # main program #-------------------------------------------------------------------- oFileName = "ncSeasMap.kml" #-------------------------------------------------------------------- # get location data #-------------------------------------------------------------------- locations = [] locationData.each do | loc | locations << Location.new(loc[0], loc[1], loc[2], loc[3], loc[4]) end #-------------------------------------------------------------------- # write the output file #-------------------------------------------------------------------- dateTime = Time.now.gmtime.strftime("Scraped at %H:%M UTC on %a, %b %d %Y.") #------------------------------------------------------------------ # the header #------------------------------------------------------------------ kmlHeader = < North Carolina Seas North Carolina Seas 1 Seas of North Carolina. KML_HEADER #------------------------------------------------------------------ # #------------------------------------------------------------------ kmlTrailer = < KML_TRAILER #------------------------------------------------------------------ # #------------------------------------------------------------------ File.open(oFileName,"w") { | file | file.puts(kmlHeader) #------------------------------------------------------------------ # #------------------------------------------------------------------ locations.each { |location| kmlEntry = < #{location.name} #boogie-board-icon #{location.weather}

#{location.seas}
Full Sea Forecast at NOAA

#{dateTime}

]]>
#{location.long},#{location.lat},0 KML_ENTRY file.puts(kmlEntry) } file.puts(kmlTrailer) } #-------------------------------------------------------------------- # write summary #-------------------------------------------------------------------- puts "Wrote #{locations.size} locations to #{oFileName}"