星期二, 五月 01, 2012

用RJSONIO包调用天气数据


JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。易于阅读和编写,同时也易于机器解析和生成。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。这些特性使JSON成为理想的数据交换语言。目前有许多API服务提供了JSON的数据格式。

如果我们要在R语言中处理json数据,可以采用的扩展包有rjson和rjsonio两个包。从本人感觉来看,rjsonio包要更为友好一些,读取之后可以直接转为简单的list格式,方便调用数据。rjson的话也可以转为list,但其中层次关系复杂,不大方便处理。下面我们用一个例子来看看如何用RJSONIO包调用数据。我们希望编一个函数从wunderground的API调用本地城市的天气预报。其基本步骤如下:
  • 若用户未输入城市名,则根据本机IP地址来返回当地天气;
  • 若用户输入了城市名,则先用google API得到城市经纬度;
  • 再用经纬度作查询参数,来返回该城市天气。

运行函数的结果看起来就象下面这样:

> getweather('wuhan')
$城市
[1] "武漢市, Hubei"

$当前
[1] "20°C 晴"

$明天
[1] "27°C-18°C 可能有雨"

Google也有提供天气预报的API,但是数据不是很丰富。wunderground提供的数据则相当丰富,它的天气API也被数据源手册所推荐。该API也可以采用城市名称作为输入,但有时候不大灵光,所以转而用经纬度作输入参数。使用这个API还要注意一点,其免费账户的限制是每分钟10次调用,超出会有警告邮件发出来。

R代码如下:(RSS用户看不到代码,是因为代码存放在gist.github.com上,然后以js形式放在博客中,你可以点这里观看。另外如果要运行这个程度,需要将yourkey换成你自己申请的key,输入的城市名两边要加引号)
# 加载所需扩展包
library(RCurl)
library(RJSONIO)
library(XML)
# 建立一个根据网址提取天气预报的子函数
fromurl<- function(finalurl) {
# 先读取网页,再解析JSON数据存在raw中
web <- getURL(finalurl)
raw <-fromJSON(web)
high <- raw$forecast$simpleforecast$forecastday[[2]]$high['celsius']
low <- raw$forecast$simpleforecast$forecastday[[2]]$low['celsius']
condition <- raw$forecast$simpleforecast$forecastday[[2]]$conditions
currenttemp <- raw$current_observation$temp_c
currentweather <- raw$current_observation$weather
city <- as.character(raw$current_observation$display_location['full'])
result <-list(city=city,current=paste(currenttemp,'°C ',currentweather,sep=''),
tomorrow=paste(high,'°C','-',low,'°C ',condition,sep=''))
names(result) <-c('城市','当前', '明天')
return(result)
}
# 提取天气预报的主函数
getweather <- function(city='') {
# 如果用户输入为空,则根据IP地址来查询
if (city == '') {
finalurl <- 'http://api.wunderground.com/api/yourkey/conditions/
forecast/lang:CN/q/autoip.json'
return(fromurl(finalurl))
# 否则就调用google API,这时需要用XML包来解析数据得到经纬度
} else {
requestUrl<-paste("http://maps.googleapis.com/maps/api/geocode/xml?address="
,city,"&sensor=false", sep="")
xmlResult<-xmlTreeParse(requestUrl,isURL=TRUE)
root <- xmlRoot(xmlResult)
lat <-xmlValue(root[['result']][['geometry']][['location']][['lat']])
lon <-xmlValue(root[['result']][['geometry']][['location']][['lng']])
url <- 'http://api.wunderground.com/api/yourkey/conditions/forecast/lang:CN/q/'
# 将经纬度与其它信息相结合,形成查询地址
finalurl <- paste(url,as.character(lat),',',as.character(lon),'.json',sep='')
return(fromurl(finalurl))
}
}
view raw weather.R hosted with ❤ by GitHub

2 条评论:

  1. 我有个问题 在不输入城市的时候,发现服务端没有正确返回,但是通过浏览器去请求的时候,发现是有数据返回的,我在想是不是因为RCurl 需要设置请求头等信息?

    回复删除
    回复
    1. 这个API有可能改过了,目前的程序不一定适用,不过对于这种简单的静态页面应该不需要设置请求头信息。

      删除