##!/usr/bin/env python # xmlweather.cgi is a python cgi script that parses National Weather Service XML weather data and displays it in a web page. # Set the url variable with the weather station of your choice. I include this in webpages using server-side includes with the # following statement: Notice also that you'll need to create a directory for the image # cache and a file for the xml cache. Both need to be writable by apache. # Enjoy. http://www.braggtown.com ## Import Python modules import cgi, cgitb; cgitb.enable() from urllib import urlopen, urlretrieve from xml.dom import minidom from sys import exit import os from os.path import exists, join, split from time import time ## Set url variable. Get url from http://www.nws.noaa.gov/data/current_obs/ url = "http://www.nws.noaa.gov/data/current_obs/KRDU.xml" ## Set cache variable to True to use local cache, False to always retrieve newest file useCache = True ## Set variable to location of locally cached xml file cache = "/home/jtuttle/public_html/weather_cache.xml" ## Set image directory. This reduces network latency by utilizing local image directory. Set to False if no local images. imgDir = "/home/jtuttle/public_html/images" imgDirUrl = "http://www.prairienet.org/~jtuttle/images/weather_icons" # Acquire, parse, and normalize xml from NWS. Return xml tree object def getWebXML(url): try: content = urlopen(url).read() xml = minidom.parseString(content) xml.normalize() return xml except IOError: print "Content-Type: text/html\n" print " No valid data at ", url exit() # Acquire, parse, and normalize xml from local cached file. Return xml tree object def getCacheXML(cache): xml = minidom.parse(cache) xml.normalize() return xml # Parse out selected elements and populate variables. Return variable dictionary def getElements(xml): root = xml.getElementsByTagName('current_observation') imgroot = xml.getElementsByTagName('image') location = (root[0].getElementsByTagName('location')[0]).childNodes[0].data.encode('iso-8859-1') weather = (root[0].getElementsByTagName('weather')[0]).childNodes[0].data.encode('iso-8859-1') temperature_string = (root[0].getElementsByTagName('temperature_string')[0]).childNodes[0].data.encode('iso-8859-1') relative_humidity = (root[0].getElementsByTagName('relative_humidity')[0]).childNodes[0].data.encode('iso-8859-1') wind_string = (root[0].getElementsByTagName('wind_string')[0]).childNodes[0].data.encode('iso-8859-1') heat_index_string = (root[0].getElementsByTagName('heat_index_string')[0]).childNodes[0].data.encode('iso-8859-1') observation_time = (root[0].getElementsByTagName('observation_time')[0]).childNodes[0].data.encode('iso-8859-1') credit = (root[0].getElementsByTagName('credit')[0]).childNodes[0].data.encode('iso-8859-1') credit_URL = (root[0].getElementsByTagName('credit_URL')[0]).childNodes[0].data.encode('iso-8859-1') img_url = (imgroot[0].getElementsByTagName('url')[0]).childNodes[0].data.encode('iso-8859-1') if (imgDir) and exists(imgDir): img_url = cacheIcons(imgDir, img_url, imgDirUrl) img_title = (imgroot[0].getElementsByTagName('title')[0]).childNodes[0].data.encode('iso-8859-1') img_link = (imgroot[0].getElementsByTagName('link')[0]).childNodes[0].data.encode('iso-8859-1') icon_url_base = (root[0].getElementsByTagName('icon_url_base')[0]).childNodes[0].data.encode('iso-8859-1') icon_url_name = (root[0].getElementsByTagName('icon_url_name')[0]).childNodes[0].data.encode('iso-8859-1') icon_url = join(icon_url_base, icon_url_name) if (imgDir) and exists(imgDir): icon_url = cacheIcons(imgDir, icon_url, imgDirUrl) elDict = {'location': location, 'weather': weather, 'temperature_string': temperature_string, 'relative_humidity': relative_humidity,\ 'wind_string': wind_string, 'heat_index_string': heat_index_string, 'observation_time': observation_time, 'credit': credit, \ 'credit_URL': credit_URL, 'img_url': img_url, 'img_title': img_title, 'img_link': img_link, 'icon_url': icon_url} return elDict # Determine if local cache of icon exists. If not, copy to image cache directory def cacheIcons(imgDir, url, imgDirUrl): path, icon = split(url) if not exists(join(imgDir,icon)): urlretrieve(url, join(imgDir, icon)) return join(imgDirUrl, icon) # Format results and xhtml in verbose fashion def formatDataVerbose(elDict, url): print "Content-Type: text/html\n" print """weather icon
\n""" \ % (elDict["icon_url"]) print "

Local conditions at %s : %s


\n" % (elDict["location"], elDict["observation_time"]) print "The weather is %s and the temperature is %s." % (elDict["weather"].lower(), elDict["temperature_string"]) print "The heat index is %s, the relative humidity is %s, and the wind is %s.
\n" % (elDict["heat_index_string"].lower(), \ elDict["relative_humidity"].lower(), elDict["wind_string"].lower()) print """
%s""" % (elDict["img_link"], elDict["img_title"], \ elDict["img_url"], elDict["img_title"]) print "" % (url) # Format results and xhtml in succint fashion def formatDataSuccinct(elDict, url): print "Content-Type: text/html\n" print """weather icon

""" \ % (elDict["icon_url"]) print "Local conditions at %s : %s
\n" % (elDict["location"], elDict["observation_time"]) print "Current conditions: ", elDict["weather"], "
" print "Temperature: ", elDict["temperature_string"], "
" print "Relative Humidity: ", elDict["relative_humidity"], "%
" print "Heat Index: ", elDict["heat_index_string"], "
" print "Wind: ", elDict["wind_string"], "
\n" print """
%s
""" % (elDict["img_link"], elDict["img_title"], \ elDict["img_url"], elDict["img_title"]) print "" % (url) # Determine age of cached file. If older than 1 hour, retrieve new data def checkCacheAge(url, cache): cache_age = os.path.getmtime(cache) if ((time() - cache_age)/60 > 30): content = urlopen(url) f = open(cache, 'w') f.write(content.read()) content.close() f.close() ## main logic if (useCache) and (exists(cache)): checkCacheAge(url, cache) xml = getCacheXML(cache) else: xml = getWebXML(url) elDict = getElements(xml) #formatDataVerbose(elDict, url) formatDataSuccinct(elDict, url)