這兩天看了下如何獲取天氣預報,寫篇文章總結下:
Weather.com有如下三個Json格式的查詢接口,以北京為例:
直接訪問它就可以獲取到Json格式的數據,解析后就可以用了。其中第三個m.weather.com.cn的信息最全,其它的幾個做一個當天的天氣預報也夠用了。要獲取其它城市的天氣,只需要把標紅的城市ID改成其它ID即可,至於城市的ID如何獲取,下面就簡單的介紹一下。
ID是一個9位的數字,按照長度可以分為如下四部分:
101(國家代號) 01(省) 01(二級地區) 00(三級地區)
其中前面三位國家代號101是固定的,無需獲取。關鍵是獲取后面三級地區編碼代號。要獲取所有的地區代碼,可以通過如下地址獲取:
http://m.weather.com.cn/data5/city0101.xml
它有一個參數,就是地區代號,返回的是下一級的地區代號。另外,雖然它的uri格式是一個xml,實際上返回的可不是xml,而是一個類似"01|北京,02|上海,03|天津,04|重慶"的格式化的字符串,不過也很好解析就是啦。
要獲取所有的地區代號,可以通過如下方式:
-
訪問http://m.weather.com.cn/data5/city.xml得到所有省的編號(示例:01|北京,02|上海,03|天津)
-
根據省的編號獲取所有二級地區的編號,以北京為例,訪問http://m.weather.com.cn/data5/city01.xml即可。
-
根據二級編號訪問即可獲取三級編號,示例:http://m.weather.com.cn/data5/city0101.xml。
有了上述基礎后,我們就可以簡單的寫一個小程序獲取所有城市的ID了
class CityInfo
{
public string Name { get; private set; }
public string Id { get; private set; }
private CityInfo() //這個對象不能被外部創建
{
}
public override string ToString()
{
return string.Format("[{0}, {1}]", Name, Id);
}
static HttpClient httpClient = new HttpClient();
async Task<CityInfo[]> GetSubCitiesAsync()
{
var requestUrl = string.Format("http://m.weather.com.cn/data5/city{0}.xml", Id);
var result = await httpClient.GetStringAsync(requestUrl);
var cityInfo = from city in result.Split(',')
let data = city.Split('|')
select new CityInfo() { Id = data[0], Name = data[1] };
return cityInfo.ToArray();
}
static async Task<IEnumerable<CityInfo>> GetSubCitiesAsync(IEnumerable<CityInfo> cities)
{
var tasks = cities.Select(i => i.GetSubCitiesAsync());
await Task.WhenAll(tasks);
return tasks.Select(i => i.Result).SelectMany(i => i);
}
public static async Task<IEnumerable<CityInfo>> GetAllCitiesAsync()
{
var root = new CityInfo(); //空對象為0級對象
var level1Cities = await root.GetSubCitiesAsync();
var level2Cities = await GetSubCitiesAsync(level1Cities);
var level3Cities = await GetSubCitiesAsync(level2Cities);
return level3Cities;
}
}
這個類使用非常簡單,它就只有一個接口GetAllCitiesAsync(),通過它可以返回所有三級城市的ID。
foreach (var item in await CityInfo.GetAllCitiesAsync())
{
Console.WriteLine(item);
}
由於獲取速度主要依賴於網絡,我這里的邏輯做得比較簡單,並沒有刻意追求最高效率。簡單的試了下,大概20s左右能返回結果,總共有2564個城市,這么看來網上的那份城市ID列表是不全的。
關於城市列表,我這里就不貼了,有需要的自己把我上面的代碼運行一下即可(需要.net 4.5環境)。