A little more advanced CGI
You saw in the
Basic CGI Scripting tip how to
create an HTML form and connect it to a Python script. That Python program would then process some part of the form input and return some HTML that the Web server sends back to the browser. It's not necessary to separate the HTML form from the Python program, however. Sometimes it may make things simpler to combine them.
Here's a CGI version of our Weather Grabber program. Notice that the programming logic is unchanged from the original weather program. Like the previous example, the major difference is changing the lines that print to the screen to lines that create a new string that will be substituted into the HTML.
The script
#!/usr/bin/python
import urllib2, string, cgi
header = "Content-Type: text/html\n\n"
reshtml = """<html>
<head><title>%s Weather Conditions</title></head>
<body>
<h1>Current weather conditions for %s</h1>
%s
</body>
</html>"""
errorhtml = """<html>
<head><title>Weather retrieval error for %s</title></head>
<body>
<h1>No data available</h1>
<p>There doesn't appear to be a station named %s.</p>
</body>
</html>"""
formhtml = """<html>
<head><title>METAR Weather conditions</title></head>
<body>
<h1>Current weather conditions</h1>
<form action="weather2.py">
Enter a METAR station ID
<input name="station" width="5" size="5">
<input type="submit">
<input type="reset">
</form>
</body>
</html>"""
def getData(stationID):
"""
Return a list of METAR data.
Argument
station -- four-letter METAR station code
"""
noaa_url = "ftp://weather.noaa.gov/data/observations/metar/stations/"
url = noaa_url + stationID + ".TXT"
f = urllib2.urlopen(url).read()
data = string.split(f)
return data
def CtoF(Ctemp):
"""
Convert a Celsius temperature to Fahrenheit
"""
return (9.0/5)*Ctemp+32
def FtoC(Ftemp):
return (5.0/9)*(Ftemp-32)
def parseTemps(s):
temp, dewPt = string.split(s, "/")
if temp[0] == 'M':
temp = -1*int(temp[1:])
else:
temp = int(temp)
if dewPt[0] == 'M':
dewPt = -1*int(dewPt[1:])
else:
dewPt = int(dewPt)
return temp, dewPt
def getWindDir(s):
if s == 'VRB':
return s
else:
dir = int(s)
if 348.75 < dir < 360 or 0 < dir < 11.25: return "N"
elif 11.25 <= dir < 33.75: return "NNE"
elif 33.75 <= dir < 56.25: return "NE"
elif 56.25 <= dir < 78.75: return "ENE"
elif 78.75 <= dir < 101.25: return "E"
elif 101.25 <= dir < 123.75: return "ESE"
elif 123.75 <= dir < 146.25: return "SE"
elif 146.25 <= dir <168.75: return "SSE"
elif 168.75 <= dir < 191.25: return "S"
elif 191.25 <= dir < 213.75: return "SSW"
elif 213.75 <= dir < 236.25: return "SW"
elif 236.25 <= dir < 258.75: return "WSW"
elif 258.75 <= dir < 281.25: return "W"
elif 281.25 <= dir < 303.75: return "WNW"
elif 303.75 <= dir < 326.25: return "NW"
else: return "NNW"
def parseWind(s):
windDir = getWindDir(s[:3])
windSpd = s[3:-2]
windGust = 0
if "G" in windSpd:
windSpd, windGust = string.split(windSpd, "G")
return windDir, int(windSpd), int(windGust)
def calcWindChill(temp, windSpd):
T = CtoF(temp)
V = windSpd * 1.15 # convert to mph
windChill = 35.75 + 0.6215*T - 35.75*V**0.16 + .4275*T*V**0.16
return windChill
def makeTable(data):
"""
Generate HTML table containing the last reported weather conditions.
Argument
data -- list of METAR codes
"""
s = ''
date = data[0]
time = data[1]
station = data[2]
data = data[3:] # slice off first four items since they're always the same
for item in data:
if "/" in item and item[-2:] != 'SM':
temp, dewPt = parseTemps(item)
elif item[-2:] == 'KT':
windDir, windSpd, windGust = parseWind(item)
elif item[0] == 'A' and item != 'AUTO':
pressure = float(item[1:])/100
elif item == 'RMK':
break
# Print weather conditions
s += "<table border='1' cellpadding='5'>\n"
s += "<tr><th>Last observation</th> \
<td>%s at %s GMT</td></tr>\n" % (date, time)
s += "<tr><th>Temperature</th> \
<td>%s °C (%.0f °F)</td></tr>\n" % (temp, CtoF(temp))
s += "<tr><th>Dew point</th> \
<td>%s °C (%.0f °F)</td></tr>\n" % (dewPt, CtoF(dewPt))
if windSpd == 0:
s += "<tr><th>Wind</th><td>calm</td></tr>\n"
else:
if windDir == "VRB":
s += "<tr><th>Wind</th><td>variable"
else:
s += "<tr><th>Wind</th><td>%s " % windDir
if windGust == 0:
s += "at %s mph (%.0f knots)</td></tr>\n" % (windSpd, windSpd*1.15)
else:
s += "at %s mph (%.0f knots) gusting to \
%s mph (%.0f knots)</td></tr>\n" \
% (windSpd, windSpd*1.15, windGust, windGust*1.15)
if windSpd*1.15 >= 5 and CtoF(temp) <= 40:
windChill = calcWindChill(temp, windSpd)
s += "<tr><th>Wind chill</th> \
<td>%.0f °C (%.0f °F)</td></tr>\n" \
% (FtoC(windChill), windChill)
s += "<tr><th>Pressure</th><td>%.2f in. of Hg</td></tr>\n" % pressure
s += "</table>\n"
return s
def main():
form = cgi.FieldStorage()
if form.has_key('station'):
station = string.upper(form['station'].value)
try:
conditions = getData(station)
print header + reshtml % (station, station, makeTable(conditions))
except IOError:
print header + errorhtml % (station, station)
else:
print header + formhtml
if __name__ == '__main__':
main()
|