Monday, 21 March 2011

Finding the Weather with YQL and the Yahoo API

I spent some of this weekend examining the potential of the Google API for finding out the weather in my area. My long term aim is to include some nod to local weather in a Flash app I am working on. While the Google API was easy to tap into (see here) it is not very well documented and apparently unofficial and may change or vanish without warning (see discussion here) - which wouldn't bode well for inclusion in an app.

It was Jason Emerick's blog that pointed me towards the Yahoo API as an alternative with better documentation and official support. Now I have always been a fan of Google over Yahoo, but needing reliability I sloped over to Yahoo and revived my dormant account. It wasn't long before I was utterly convinced that Yahoo have an excellent API with excellent support, and a terrific console to help you try out your queries and test the results.

Differences between getting Google weather and Yahoo weather

While powerful, the Yahoo API didn't give me the weather information I was after with quite the same ease as the Google API. With the Google API all you needed to do is call the API URL and append your location to the end:

http://www.google.com/ig/api?weather=london,uk

The results are XML you can parse using your chosen language (in my case ActionScript).

Yahoo on the other hand isn't quite as straightforward (though much better once you get the hang of it). This is because you can't directly query Yahoo's weather API using your chosen location as you can with Google. Yahoo instead requires you to specify the WOEID (Yahoo's proprietary "Where On Earth ID") of the location you want to know the weather for.

Once you know the WOEID of the location, finding the weather for that location is as simple as:

http://weather.yahooapis.com/forecastrss?w=44418&u=c

WOEIDs appear to be an invention of Yahoo for identifying locations. Actually they are a really good idea, as it means your query will always work, even when places and names change.

The challenge is, of course, that most people won't know what the WOEID for their location is and so won't be able to use it to find out the weather in their area. I don't know my WOEID, that's for sure.

So we have to first find out our WOEID from our known location. You can do that like this:

http://query.yahooapis.com/v1/public/yql?q=select%20woeid%20from%20geo.places%20where%20text%3D%22SW1A%202AA%2Cuk%22&diagnostics=true

The Yahoo API console is very helpful in letting you experiment with the queries, and producing URLs like the one above for you to call in your code.

So knowing that with 2 questions I can still get the information I need from Yahoo, I felt more confident pressing ahead with the Yahoo API with its better documentation and promise to give 6 months notice to any changes. A far cry from Google's relative silence on the issue with their unofficial weather API.

Using ActionScript to query the Yahoo geo and weather APIs

So ultimately I have to ask 2 questions of Yahoo with my ActionScript. First - what is the WOEID for my location given as postcode, country? Second - what is the weather forecast for this WOEID?

For question 1 my ActionScript will use this query via the Yahoo YQL API to find out the location's WOEID:

http://query.yahooapis.com/v1/public/yql?q=select%20woeid%20from%20geo.places%20where%20text%3D%22SW1A 2AA%2Cuk%22&diagnostics=true

For question 2 my ActionScript will simply reference Yahoo's weather API using the WOEID from question 1 as a query term, resulting in an XML file containing weather information for the location represented by that WOEID:

http://weather.yahooapis.com/forecastrss?w=26355493&u=c

The trick with the ActionScript is to ask the questions in the right order, and to write your code so question 2 is not asked until it has the answer to question 1 (else you won't get a proper reply and your ActionScript won't get the XML it is expecting and will return 'undefined' where you were expecting the weather status).

Here's my solution, read the comments to see what I am doing there:


/*Accessing the Yahoo API to find out the weather in any location using postcode and country code*/
/*set the search terms as variables, you can pull these from user input with some different ActionScript */
var zip = "SW1A 2AA";
var country = "uk";
/*Find the WOEID*/
woeidXml = new XML ();
woeidXml.ignoreWhite = true;
/* run the loadWoeid function when the XML file loads that contains Yahoo's reply to our query below*/
woeidXml.onLoad = loadWoeid;
/* ASK QUESTION 1 - query the Yahoo API using YQL and the search terms above */
woeidXml.load ("http://query.yahooapis.com/v1/public/yql?q=select%20woeid%20from%20geo.places%20where%20text%3D%22" + zip + "%2C" + country + "%22&diagnostics=true");
/* this function will run when the XML file loads that contains Yahoo's reply to our query */
function loadWoeid () {
/*parse the XML response and store the woeid value as a variable in Flash called 'woeid'*/
woeid = woeidXml.childNodes[0].childNodes[1].childNodes[0].childNodes[0].childNodes[0];
/*test the value we have stored with a trace*/
trace (woeid);
/*find the WEATHER from the WOEID just gathered*/
/* we nest this function for question 2 within the function for question 1 because doing it this way means that question 2 is not asked until question 1 has an answer*/
weatherXml = new XML ();
weatherXml.ignoreWhite = true;
/* run the loadWeather function when the XML file loads that contains Yahoo's reply to our query below*/
weatherXml.onLoad = loadWeather;
/* ASK QUESTION 2 - query the Yahoo Weather API using the woeid we found out in question 1 above */
weatherXml.load ("http://weather.yahooapis.com/forecastrss?w=" + woeid + "&u=c");
/* this function will run when the XML file loads that contains Yahoo's reply to our query */
function loadWeather () {
/*parse the XML response and store the current weather condition value as a variable in Flash called 'condition_xml'*/
condition_xml = weatherXml.childNodes[0].childNodes[0].childNodes[12].childNodes[5].attributes.text;
/*parse the XML response and store the current weather place name value as a variable in Flash called 'place_xml'*/
place_xml = weatherXml.childNodes[0].childNodes[0].childNodes[6].attributes.city;
/*test the values we have stored with a couple of traces*/
trace (condition_xml);
trace (place_xml);
}
}


And that's a wrap. Ideally I wanted to get a single answer from Yahoo by linking the 2 questions in their API, but that proved difficult using just YQL because Yahoo would not provide weather data using YQL unless you knew the location (another apparently random code different again to the woeid) or you provided a US zip code (so no good to us Europeans). So I settled on this 2 stage solution that works for me.

Bugs or traits include being able to swap where I input a postcode with the name of a city, and you still get working results from Yahoo provided it has heard of the city.

Anyway, I know how I will use this, so if you have a use for this happy coding.

Addendum

Here's an implementation of the above code that takes user input and delivers the result.

1 comment:

  1. Anonymous27/6/11 05:39

    http://weather.yahooapis.com/forecastrss?w=44418&u=c will give forecast for only two days. But what for 2 or more days, for example i need it for 5 days

    ReplyDelete