/// <summary> /// This function doesn't technically use wunderground's api. Instead it uses a normal web request to a csv file. /// A limitation of this approach is that we would have to read through each day and decide if a significant event happened /// on that day from the data given. /// Right now this function just returns all data for a given day. /// </summary> /// <returns>Weather Incidents for the location</returns> public IEnumerable<WeatherIncident> GetEvents(string airportCode, DateTime date, WeatherIncidentType? typeToFilter) { string requestUrl = string.Format(WeatherHistoryCsvUrl, airportCode, date.Year, date.Month, date.Day); string response = WebClient.DownloadString(requestUrl); return ParseWundergroundResponse(airportCode, response, date, typeToFilter); }
public WeatherIncident(IEnumerable <Address> locations, WeatherIncidentType eventType , DateTime date, Uri moreInformationUrl) { Locations = locations; EventType = eventType; Date = date; MoreInformationUrl = moreInformationUrl; }
public WeatherIncident(IEnumerable<Address> locations, WeatherIncidentType eventType , DateTime date, Uri moreInformationUrl) { Locations = locations; EventType = eventType; Date = date; MoreInformationUrl = moreInformationUrl; }
private static IEnumerable <WeatherIncident> ParseWundergroundResponse(string airportCode, string responseString, DateTime date, WeatherIncidentType?typeToFilter) { var moreInfoUrl = new Uri(string.Format(WeatherHistoryUrl, airportCode, date.Year, date.Month, date.Day)); Airport currentAirpot = AirportList.GetAirport(airportCode); var locationOfAirport = Address.Search(string.Empty, currentAirpot.City, currentAirpot.State.Abbreviation, string.Empty, false); // Remove HTML comments and line breaks responseString = Regex.Replace(responseString, "<!--.*?-->", string.Empty, RegexOptions.Singleline).Replace("<br />", ""); IEnumerable <string> rows = responseString.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); rows = rows.Skip(1); // Skip header row var incidents = new List <WeatherIncident>(); foreach (string row in rows) { var entry = new WeatherUndergroundEntry(date, row); WeatherIncidentType incidentType = WeatherIncidentClassifier.Classify(entry); if (typeToFilter != null) { if (incidentType == typeToFilter) { incidents.Add(new WeatherIncident(locationOfAirport, incidentType, date, moreInfoUrl)); } } else { if (incidentType != WeatherIncidentType.Unclassified) { incidents.Add(new WeatherIncident(locationOfAirport, incidentType, date, moreInfoUrl)); } } } return(incidents); }
private static IEnumerable<WeatherIncident> ParseWundergroundResponse(string airportCode, string responseString, DateTime date, WeatherIncidentType? typeToFilter) { var moreInfoUrl = new Uri(string.Format(WeatherHistoryUrl, airportCode, date.Year, date.Month, date.Day)); Airport currentAirpot = AirportList.GetAirport(airportCode); var locationOfAirport = Address.Search(string.Empty, currentAirpot.City, currentAirpot.State.Abbreviation, string.Empty, false); // Remove HTML comments and line breaks responseString = Regex.Replace(responseString, "<!--.*?-->", string.Empty, RegexOptions.Singleline).Replace("<br />", ""); IEnumerable<string> rows = responseString.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); rows = rows.Skip(1); // Skip header row var incidents = new List<WeatherIncident>(); foreach (string row in rows) { var entry = new WeatherUndergroundEntry(date, row); WeatherIncidentType incidentType = WeatherIncidentClassifier.Classify(entry); if (typeToFilter != null) { if (incidentType == typeToFilter) { incidents.Add(new WeatherIncident(locationOfAirport, incidentType, date, moreInfoUrl)); } } else { if (incidentType != WeatherIncidentType.Unclassified) { incidents.Add(new WeatherIncident(locationOfAirport, incidentType, date, moreInfoUrl)); } } } return incidents; }
public IEnumerable<WeatherIncident> GetEvents(State state, string county, DateTime startDate, DateTime endDate, WeatherIncidentType? filter) { // hardcoded url that we scrape the data from const string baseNcdcUrl = "http://www4.ncdc.noaa.gov/cgi-win/wwcgi.dll?wwevent~storms"; // the post parameters for making the call string parameters = string.Format("bdate={0}%2F{1}%2F{2}&edate={3}%2F{4}%2F{5}&STATE={6}&County={7}&ETYPE=*All&fscale=*All&hamt=&wspd=&injuries=&deaths=&pdamage=&cdamage=&Send=List+Storms" , startDate.Month, startDate.Day, startDate.Year, endDate.Month, endDate.Day, endDate.Year, state.Abbreviation, county); byte[] postData = Encoding.ASCII.GetBytes(parameters); // make a POST request to the url with the parameters given var request = WebRequest.Create(baseNcdcUrl) as HttpWebRequest; request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = postData.Length; // write the post data Stream requestStream = request.GetRequestStream(); requestStream.Write(postData, 0, postData.Length); requestStream.Close(); // load the html response HtmlNode node; using (var response = request.GetResponse() as HttpWebResponse) { var reader = new StreamReader(response.GetResponseStream()); var doc = new HtmlDocument(); doc.LoadHtml(reader.ReadToEnd()); // the description below is the best I could find in xpath that would describe the table of weather events // we may want to pull the string out into a config file node = doc.DocumentNode.SelectSingleNode( "//table[@summary='This Table displays the Events Query output by state and date.']"); } if (node != null) { // This goes through each row and pulls out the location and event type // This is fragile because we are depending on the html of the response var returnValues = (from weatherEvent in node.SelectNodes("tr") where weatherEvent.SelectSingleNode("td[@headers]") != null let location = weatherEvent.SelectSingleNode("td[@headers='h1']/a").InnerText.Trim() select new WeatherIncident( Address.Search(_zoneLookup.IsZone(location) ? location : location + ", " + state.Abbreviation), WeatherIncidentClassifier.Classify( weatherEvent.SelectSingleNode("td[@headers='h4']").InnerText.Trim()), DateTime.Parse( weatherEvent.SelectSingleNode("td[@headers='h2']").InnerText.Trim()), new Uri( weatherEvent.SelectSingleNode("td[@headers='h1']/a").Attributes["href"].Value.Trim())) ); if(filter != null) { returnValues = (from weatherEvent in returnValues where weatherEvent.EventType == filter select weatherEvent); } return returnValues; } return new WeatherIncident[0]; }