转自:http://www.cnblogs.com/TianFang/archive/2013/01/03/2842913.html
这两天看了下如何获取天气预报,写篇文章总结下:
Weather.com有如下三个Json格式的查询接口,以北京为例:
直接访问它就可以获取到Json格式的数据,解析后就可以用了。其中第三个m.weather.com.cn的信息最全,其它的几个做一个当天的天气预报也够用了。要获取其它城市的天气,只需要把标红的城市ID改成其它ID即可,至于城市的ID如何获取,下面就简单的介绍一下。
ID是一个9位的数字,按照长度可以分为如下四部分:
101(国家代号) 01(省) 01(二级地区) 00(三级地区)
其中前面三位国家代号101是固定的,无需获取。关键是获取后面三级地区编码代号。要获取所有的地区代码,可以通过如下地址获取:
http://m.weather.com.cn/data5/city 0101.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/city 01.xml 即可。
-
根据二级编号访问即可获取三级编号,示例: http://m.weather.com.cn/data5/city 0101.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环境)。