12.5 Web数据

互联网上包含了大量数据,但如果你想手动访问网站下载那里的数据文件,然后再把它从硬盘中读取到R中,这一系列动作需要大量的手动操作(且也不易扩展)。

幸好,R有很多种方式可以从网络源导入数据并以编程的方式检索数据,这就使数据处理的工作事半功倍。

12.5.1 拥有API的网站

有一些包可通过网站的API接口直接下载数据到R系统。例如,世界银行已在其网站上公开了它的世界发展指标数据,WDI包可以让你轻松地在R中将这些数据导入。要运行以下例子,你需要先安装WDI包:

  1. install.packages("WDI")
  2. library(WDI)
  3. # 列出所有可用的数据集
  4. wdi_datasets <- WDIsearch()
  5. head(wdi_datasets)
  6. ## indicator
  7. ## [1,] "BG.GSR.NFSV.GD.ZS"
  8. ## [2,] "BM.KLT.DINV.GD.ZS"
  9. ## [3,] "BN.CAB.XOKA.GD.ZS"
  10. ## [4,] "BN.CUR.GDPM.ZS"
  11. ## [5,] "BN.GSR.FCTY.CD.ZS"
  12. ## [6,] "BN.KLT.DINV.CD.ZS"
  13. ## name
  14. ## [1,] "Trade in services (% of GDP)"
  15. ## [2,] "Foreign direct investment, net outflows (% of GDP)"
  16. ## [3,] "Current account balance (% of GDP)"
  17. ## [4,] "Current account balance excluding net official capital grants (% of GDP)"
  18. ## [5,] "Net income (% of GDP)"
  19. ## [6,] "Foreign direct investment (% of GDP)"
  20. # 取其中一个
  21. wdi_trade_in_services <- WDI(
  22. indicator = "BG.GSR.NFSV.GD.ZS"
  23. )
  24. str(wdi_trade_in_services)
  25. ## 'data.frame': 1764 obs. of 4 variables:
  26. ## $ iso2c : chr "1A" "1A" "1A" "1A" ...
  27. ## $ country : chr "Arab World" "Arab World" "Arab World" ...
  28. ## $ BG.GSR.NFSV.GD.ZS : num 17.5 NA NA NA ...
  29. ## $ year         : num 2005 2004 2003 2002 ...

SmarterPoland包提供了类似的功能,它封装了波兰政府的数据。使用quantmod包可以访问股票行情(默认是雅虎的数据,也可以选择其他几个数据源):

  1. library(quantmod)
  2. # 如果你正在使用0.5.0之前的版本,那么请设置以下选项,
  3. # 或者把参数auto.assign = FALSE传给getSymobols。
  4. options(getSymbols.auto.assign = FALSE)
  5. microsoft <- getSymbols("MSFT")
  6. head(microsoft)
  7. ## MSFT.Open MSFT.High MSFT.Low MSFT.Close MSFT.Volume
  8. ## 2007-01-03 29.91 30.25 29.40 29.86 76935100
  9. ## 2007-01-04 29.70 29.97 29.44 29.81 45774500
  10. ## 2007-01-05 29.63 29.75 29.45 29.64 44607200
  11. ## 2007-01-08 29.65 30.10 29.53 29.93 50220200
  12. ## 2007-01-09 30.00 30.18 29.73 29.96 44636600
  13. ## 2007-01-10 29.80 29.89 29.43 29.66 55017400
  14. ## MSFT.Adjusted
  15. ## 2007-01-03 25.46
  16. ## 2007-01-04 25.42
  17. ## 2007-01-05 25.27
  18. ## 2007-01-08 25.52
  19. ## 2007-01-09 25.54
  20. ## 2007-01-10 25.29

TwitterR包能够访问Twitter账号及其微博信息。只需要事先配置好(由于Twitter的API需要你创建一个应用程序,并使用OAuth进行注册。请阅读此包的安装说明),此包就能非常容易地导入Twitter的数据并作进一步的网络分析,或假装工作而实际上只是在刷微博。

12.5.2 抓取网页

R有内置的web服务器,所以某些需要读取数据的函数默认是带有网络访问功能的。read.table(及其衍生函数,例如read.csv)接受一个URL作为参数(而不是一个本地文件),它会在导入数据之前将副本下载到一个临时文件中。例如,经济研究员Justin Rao的网站有从2002年到2008年间的NBA工资数据:

  1. salary_url <- "http://www.justinmrao.com/salary_data.csv"
  2. salary_data <- read.csv(salary_url)
  3. str(salary_data)

由于通过互联网访问一个大文件时速度可能会很慢,如果经常使用该文件,更好的策略是用download.file对要下载的文件创建一个本地副本,然后再导入:

  1. salary_url <- "http://www.justinmrao.com/salary_data.csv"
  2. local_copy <- "my local copy.csv"
  3. download.file(salary_url, local_copy)
  4. salary_data <- read.csv(local_copy)

其他更高级的网页访问方法可以在RCurl包中找到,它能访问libcurl网络客户端接口程序库。如果你的数据包含在HTML或XML页面中,而不是刚好被放在网络上的标准数据格式(如CSV)时,这一点尤其有用。

下例将从美国海军天文台时间服务部的网站上检索几个时区中的当前日期和时间。getURL函数将访问页面并将其内容以字符串的形式返回:

  1. library(RCurl)
  2. time_url <- "http://tycho.usno.navy.mil/cgi-bin/timer.pl"
  3. time_page <- getURL(time_url)
  4. cat(time_page)
  5. ## <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final"//EN>
  6. ## <html>
  7. ## <body>
  8. ## <TITLE>What time is it?</TITLE>
  9. ## <H2> US Naval Observatory Master Clock Time</H2> <H3><PRE>
  10. ## <BR>Jul. 17, 20:43:37 UTC Universal Time
  11. ## <BR>Jul. 17, 04:43:37 PM EDT Eastern Time
  12. ## <BR>Jul. 17, 03:43:37 PM CDT Central Time
  13. ## <BR>Jul. 17, 02:43:37 PM MDT Mountain Time
  14. ## <BR>Jul. 17, 01:43:37 PM PDT Pacific Time
  15. ## <BR>Jul. 17, 12:43:37 PM AKDT Alaska Time
  16. ## <BR>Jul. 17, 10:43:37 AM HAST Hawaii-Aleutian Time
  17. ## </PRE></H3><P><A HREF="http://www.usno.navy.mil"> US Naval Observatory</A>
  18. ##
  19. ## </body></html>

下一步几乎总是使用XML包中的htmlParse(或相关函数)解析页面。这使你可以提取其有用的节点。在下例中,以\n(换行符)为分隔符将得到每个时间线,使用\t(制表符)分隔则能获得时间/时区对:

  1. library(XML)
  2. time_doc <- htmlParse(time_page)
  3. pre <- xpathSApply(time_doc, "//pre")[[1]]
  4. values <- strsplit(xmlValue(pre), "\n")[[1]][-1]
  5. strsplit(values, "\t+")
  6. ## [[1]]
  7. ## [1] "Jul. 17, 20:43:37 UTC" "Universal Time"
  8. ##
  9. ## [[2]]
  10. ## [1] "Jul. 17, 04:43:37 PM EDT" "Eastern Time"
  11. ##
  12. ## [[3]]
  13. ## [1] "Jul. 17, 03:43:37 PM CDT" "Central Time"
  14. ##
  15. ## [[4]]
  16. ## [1] "Jul. 17, 02:43:37 PM MDT" "Mountain Time"
  17. ##
  18. ## [[5]]
  19. ## [1] "Jul. 17, 01:43:37 PM PDT" "Pacific Time"
  20. ##
  21. ## [[6]]
  22. ## [1] "Jul. 17, 12:43:37 PM AKDT" "Alaska Time"
  23. ##
  24. ## [[7]]
  25. ## [1] "Jul. 17, 10:43:37 AM HAST" "Hawaii-Aleutian Time"

httr包基于RCurl,它能提供了更好的语法,使我们的工作更加方便。在httr中,相当于RCurl包中getURL的函数是GETcontent函数能在检索页面内容的同时解析它。在下例中,我们将传入useInternalNodes = TRUE来模仿htmlParse的行为,并重复上例中的行为:

  1. library(httr)
  2. time_page <- GET(time_url)
  3. time_doc <- content(page, useInternalNodes = TRUE)