############################################################ # # Copyright Yves Dorfsman 2008. # # CanadianWeather.py is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # CanadianWeather.py is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See # the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with CanadianWeather.py in the COPYING-GPL file; if not, # write to the Free Software Foundation, Inc., 59 Temple Place, # Suite 330, Boston, MA 02111-1307 USA # ############################################################ # # Sends queries to the Canadian Weather Office (Environment # Canada, http://www.weatherOffice.gc.ca) to obtain data # for a given year (daily data) or month (hourly data) # and station ID, and convert to a python list. # ############################################################ class get_csv(object): ''' The CSV data from the Canadian Weather Office is always formatted with a few paragraphs separated by blank lines. At time of writing, there were three paragraphs in the case of hourly data, but two in the case of daily data. On creation of an object, the init method gets data from the given url, skip everything up to the line starting with '"Date/Time",', which is what the header of the data starts with, and this seems to be consistent regardless of the request. The header is kept as the python csv module knows how to deal with it. The csv module expects an iterator, and reads its data via the next method. ''' def __init__(self, url): import urllib f = urllib.urlopen(url) self.content = f.readlines() f.close() self.position = 0 self.end = len(self.content) text = '' while text.find('"Date/Time",') != 0: text = self.next().strip() self.position -= 1 def next(self): if self.position == self.end: raise StopIteration else: line = self.content[self.position].strip() self.position += 1 return line def __iter__(self): return self class dataList(list): ''' Takes a station ID, year (for daily values), or a year and a month (for hourly values), and return a list with the weather information for that period of time. You can find the station IDs on the Canadian Weather Office (CWO) website, under "Historical Weather", "Climate Data Online". Cities typically have several stations, active at different time throughout history. For example, in Calgary the airport station (id: 2205) is the one with the most data going all the way to 1953, while University of Calgary (id: 2320) only has data for 1964 to 1990. The same data is also available in XML format, use the same URL with "format=xml" instead of csv. ''' def __init__(self, StationID, Year, Month = None): import csv url1='http://www.climate.weatheroffice.ec.gc.ca/climateData/bulkdata_e.html?StationID=' url3='&Year=' if Month == None: # for daily data (daily max temp, min temp, etc...) the month is not # needed, all the rows are returned for the particular year at once. periodicity = 'd' url5 = '' elif 1 <= Month <= 12: periodicity = 'h' url5 = '&Month=' + str(Month) else: raise ValueError('Month has to be between 1 and 12.') url6= '&format=csv&type=' + periodicity + 'ly' url = url1 + str(StationID) + url3 + str(Year) + url5 + url6 #print url list.__init__(self) csvdata = get_csv(url) reader = csv.DictReader(csvdata) self.extend( [ e for e in reader ] )