我试图将结果运行到GET中的URL列表
lon <- as.list(seq(-124.4531, -68.02734, by=5.9180))
lat <- as.list(seq(25.7998, 49.0090, by=5.6667))
z <- expand.grid(lon,lat)
z <- as.data.frame(cbind("lon" = unlist(z$Var1), "lat" = unlist(z$Var2)))
n = dim(z)[1]
for(i in 1:n) {
for(j in 1:n) {
URL<- paste0("https://maps.googleapis.com/maps/api/place/radarsearch/json?location=", as.character(z$lat[j]), ",", as.character(z$lon[i]), "&radius=50000&name=MetroPCS&key=key")
print(URL)
}
}
loop<-function(URL){
res<-GET("URL")
jasonAnse<-contnet(res,"text")
myDataframe<- jsonlite::fromJSON(content(res,"text"))
}
myDataframe
但似乎GET功能只能运行最后一条记录。不确定循环或GET()函数是否错误。
答案 0 :(得分:0)
每当我看到一个问题说“1或更多”的东西时,我倾向于考虑做一次事情并迭代矢量或列表中的所有项目。你开始以这种方式思考,但是在你的循环中,你每次都分配 over URL
并且只保存最后一个。即使你保存了所有的URL,GET
一次只能检索一个,所以你也需要迭代该函数。
这个演示主要是概念,没有真正证据证明它有效。因为您在问题中包含了一个实际的API密钥,所以它已经用尽了。 (你可能想从问题中删除它。)无论如何,我有点相信这个概念可以将函数应用到一个列表中,所以尽管我还没有验证你从中得到了一个巨大的data.frame,也许我会幸运的。
z <- expand.grid(lon = seq(-124.4531, -68.02734, by=5.9180),
lat = seq(25.7998, 49.0090, by=5.6667))
head(z)
# lon lat
# 1 -124.4531 25.7998
# 2 -118.5351 25.7998
# 3 -112.6171 25.7998
# 4 -106.6991 25.7998
# 5 -100.7811 25.7998
# 6 -94.8631 25.7998
mapply
(和Map
)通过将来自矢量/列表的 1个或多个参数应用于单个函数(第一个参数)来工作。在某些语言中,它被认为是“拉上论据”。考虑一下:
mapply(function(x,y,z) x+y-z,
c(1,2,3,4), c(5,6,7,8), c(9,10,11,12))
对匿名函数的第一次调用将执行1+5-9
;第二,2+6-10
;使用它还有其他一些技巧,但回顾你的问题:
URLs <- mapply(sprintf,
list("https://maps.googleapis.com/maps/api/place/radarsearch/json?location=%s,%s&radius=50000&name=MetroPCS&key=AIzaSyA3u4HwTGiUsHP7FNUKkjbYcHHe1xFBDTU"),
z$lat, z$lon)
(修改:我之前在z$lat
内已z$lon
和mapply
被撤销,已修复。)
函数sprintf
接受任意数量的参数:第一个始终是格式化字符串,第二个和更远(如果有)始终是填充格式化字符串的参数/对象。 list("htt...")
参数只为sprintf
的每个调用提供了该参数,因此函数调用被分解为:
sprintf("https...", z$lon[1], z$lon[2])
sprintf("https...", z$lon[2], z$lon[2])
# ...
sprintf("https...", z$lon[50], z$lon[50])
这些调用被包裹回character
向量,长度为50。
(URLs <- head(URLs)) # doing this for a simpler demo, since I don't need all 50
# [1] "https://maps.googleapis.com/maps/api/place/radarsearch/json?location=-124.4531,25.7998&radius=50000&name=MetroPCS&key=AIzaSyA3u4HwTGiUsHP7FNUKkjbYcHHe1xFBDTU"
# [2] "https://maps.googleapis.com/maps/api/place/radarsearch/json?location=-118.5351,25.7998&radius=50000&name=MetroPCS&key=AIzaSyA3u4HwTGiUsHP7FNUKkjbYcHHe1xFBDTU"
# [3] "https://maps.googleapis.com/maps/api/place/radarsearch/json?location=-112.6171,25.7998&radius=50000&name=MetroPCS&key=AIzaSyA3u4HwTGiUsHP7FNUKkjbYcHHe1xFBDTU"
# [4] "https://maps.googleapis.com/maps/api/place/radarsearch/json?location=-106.6991,25.7998&radius=50000&name=MetroPCS&key=AIzaSyA3u4HwTGiUsHP7FNUKkjbYcHHe1xFBDTU"
# [5] "https://maps.googleapis.com/maps/api/place/radarsearch/json?location=-100.7811,25.7998&radius=50000&name=MetroPCS&key=AIzaSyA3u4HwTGiUsHP7FNUKkjbYcHHe1xFBDTU"
# [6] "https://maps.googleapis.com/maps/api/place/radarsearch/json?location=-94.8631,25.7998&radius=50000&name=MetroPCS&key=AIzaSyA3u4HwTGiUsHP7FNUKkjbYcHHe1xFBDTU"
我们仍然有一个“1或更多”的列表,因此我们可以继续使用lapply
逻辑:
HTMLs <- lapply(URLs, GET)
HTMLs[1]
# [[1]]
# Response [https://maps.googleapis.com/maps/api/place/radarsearch/json?location=-124.4531,25.7998&radius=50000&name=MetroPCS]
# Date: 2017-10-18 03:23
# Status: 200
# Content-Type: application/json; charset=UTF-8
# Size: 141 B
# {
# "error_message" : "This service requires an API key.",
# "html_attributions" : [],
# "results" : [],
# "status" : "REQUEST_DENIED"
# }
在这种情况下,我得到了一个失败(这将减少我以后可以做的事情),但是这个输出显示你的HTMLs
变量应该是50的长度,每个变量都是这样的。
继续,虽然从现在开始它没有经过测试。我相信你已经测试过这个,一次只能使用一个URL。
contents <- lapply(HTMLs, content, "text")
myDataFrames <- lapply(contents, jsonlite::fromJSON)
最后一个应该是data.frame
的列表,这很棒!我通常会做两件事之一:如果我可以轻松地将它们(rbind
?)组合成一个data.frame
,那么我会这样做:
myDataFrame <- do.call(rbind.data.frame, c(myDataFrames, list(stringsAsFactors = FALSE)))
(stringsAsFactors
的使用主要是文体,但显示如何在需要时添加参数。)
但是,如果将它们分开是有益的(可能它们不是同质结构),那么在列表上运行(重复lapply
或相关)仍然很容易。
可以通过一次调用来证明这一点的合理性:
myDataFrames <- lapply(URLs, function(u) {
html <- GET(u)
cont <- cont(html, "text")
jsonlite::fromJSON(cont)
})
这没有错。但是,特别是在开发过程中,保留不同对象的中间列表可能是有益的。