如何在 R 代码中集成 Google 距离矩阵 API 密钥? [英] How to integrate Google Distance Matrix API key in R code?

查看:43
本文介绍了如何在 R 代码中集成 Google 距离矩阵 API 密钥?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已在 Google 注册以获取更多行驶时间距离请求.但是,Google 不会自动获取每天运行 2500 多个查询的权限".此外,mapdist() 没有集成 API 密钥的参数.

I have registered in Google to obtain more requests of drive time distances. However Google doesn't automatically pick up this "permission" to run more than 2500 queries a day. In addition mapdist() doesn't have an argument to integrate an API key.

我已设法通过 Google 控制台获取 API 密钥.

I have managed to get an API key through the Google console.

我尝试修改原始代码添加密钥并更改第 56、90 和91 如下:

I tried to modify the raw code adding key and changing line 56, 90 & 91 as follows:

    mapdist <- function(from, to, mode = c("driving","walking","bicycling"),
  output = c("simple","all"), messaging = FALSE, sensor = FALSE,
  language = "en-EN", override_limit = FALSE, key = "XXXX")
{

  message("by using this function you are agreeing to the terms at :")
  message("http://code.google.com/apis/maps/documentation/distancematrix/\n")

  # check parameters
  if(is.numeric(from) && length(from) == 2) from <- revgeocode(from)
  stopifnot(is.character(from))
  if(is.numeric(to) && length(to) == 2) to <- revgeocode(to)
  stopifnot(is.character(to))
  from_to_df <- data.frame(from = from, to = to, stringsAsFactors = FALSE)
  origins <- from_to_df$from
  destinations <- from_to_df$to # this ensures # from = # to
  mode <- match.arg(mode)
  output <- match.arg(output)
  stopifnot(is.logical(messaging))
  stopifnot(is.logical(sensor))


  getdists <- function(df){

    # format url
    origin <- df$from[1]
    origin <- gsub(",", "", origin)
    origin <- gsub(" ", "+", origin)
    origin <- paste("origins=", origin, sep = "")
    destinations <- df$to
    destinations <- gsub(",", "", destinations)
    destinations <- gsub(" ", "+", destinations)
    destinations <- paste("destinations=", paste(destinations, collapse = "|"), sep = "")
    mode4url <- paste("mode=", mode, sep = "")
    lang4url <- paste("language=", language, sep = "")
    sensor4url <- paste("sensor=", tolower(as.character(sensor)), sep = "")
    keyUrl <- paste("key=", key, sep = "")
    posturl <- paste(origin, destinations, mode4url, sensor4url, keyUrl, sep = "&")
    url_string <- paste("http://maps.googleapis.com/maps/api/distancematrix/json?",
      posturl, sep = "")
    url_string <- URLencode(url_string)


    # check if query is too long
    if(nchar(url_string) >= 2048){
      n <- nrow(df)
      half_df <- floor(n/2)
      return(
        rbind(
          getdists(df[half_df,]),
          getdists(df[(half_df+1):n,])
        )
      )
    }

    # check/update google query limit
    check_dist_query_limit(url_string, elems = nrow(df),
      override = override_limit, messaging = messaging)


    # distance lookup
    if(messaging) message("trying url ", url_string)
    connect <- url(url_string)
    tree <- fromJSON(paste(readLines(connect), collapse = ""))
    close(connect)

    # message user
    message(paste0("Information from URL : ", url_string))

    # label destinations - first check if all were found
    if(length(df$to) != length(tree$destination_addresses)){
      message("matching was not perfect, returning what was found.")
      names( tree$rows[[c(1,1)]] ) <- tree$destination_addresses
      output <<- "all"
      # stringdist::amatch(df$to, tree$destination_addresses, maxDist = 10)
    } else {
      names( tree$rows[[c(1,1)]] ) <- df$to
    }

    # return
    tree$rows[[c(1,1)]]
  }

  out <- dlply(from_to_df, "from", getdists)

  # return all
  if(output == "all") return(out)



  # format output
  out <-
    ldply(out, function(oneFromList){
      ldply(oneFromList, function(oneToList){
        data.frame(
          m = oneToList$distance$value,
          km = oneToList$distance$value/1000,
          miles = 0.0006214 * oneToList$distance$value,
          seconds = oneToList$duration$value,
          minutes = oneToList$duration$value / 60,
          hours = oneToList$duration$value / 3600
        )
      })
    })

  names(out) <- c("from", "to", names(out)[3:ncol(out)])

  # "simple" return
  suppressMessages(join(from_to_df, out))
}




check_dist_query_limit <- function(url_string, elems, override, messaging){
  .GoogleDistQueryCount <- NULL; rm(.GoogleDistQueryCount); # R CMD check trick

  if(exists(".GoogleDistQueryCount", .GlobalEnv)){

    .GoogleDistQueryCount <<-
      subset(.GoogleDistQueryCount, time >= Sys.time() - 24*60*60)

    # 2500 per 24 hours
    if(sum(.GoogleDistQueryCount$elements) + elems > 2500){
      message("query max exceeded, see ?mapdist.  current total = ",
        sum(.GoogleDistQueryCount$elements))
      if(!override) stop("google query limit exceeded.", call. = FALSE)
    }

    # 100 per 10 seconds
    if(with(.GoogleDistQueryCount,
      sum(elements[time >= Sys.time() - 10]) + elems > 100
    )){
      if(messaging) message("waiting 10 seconds for another 100 queries...", appendLF=F)
      Sys.sleep(10) # can do better
      if(messaging) message(" done")
    }

    # append to .GoogleDistQueryCount
    .GoogleDistQueryCount <<- rbind(.GoogleDistQueryCount,
      data.frame(time = Sys.time(),  url = url_string,
        elements = elems, stringsAsFactors = FALSE)
    )


  } else {

    .GoogleDistQueryCount <<-
      data.frame(time = Sys.time(),  url = url_string,
        elements = elems, stringsAsFactors = FALSE)

  }
}



#' Check Google Maps Distance Matrix API query limit
#'
#' Check Google Maps Distance Matrix API query limit
#'
#' @return a data frame
#' @author David Kahle \email{david.kahle@@gmail.com}
#' @seealso \url{http://code.google.com/apis/maps/documentation/distancematrix/}
#' @export
#' @examples
#' distQueryCheck()
distQueryCheck <- function(){
  .GoogleDistQueryCount <- NULL; rm(.GoogleDistQueryCount); # R CMD check trick
  if(exists(".GoogleDistQueryCount", .GlobalEnv)){
    remaining <- 2500-sum(
      subset(.GoogleDistQueryCount, time >= Sys.time() - 24*60*60)$elements
      )
    message(remaining, " distance queries remaining.")
  } else {
    remaining <- 2500
    message(remaining, " distance queries remaining.")
  }
  invisible(remaining)
}

但是我在运行 mapdist() 时收到此错误消息:

However I got this error message when running the mapdist():

by using this function you are agreeing to the terms at :
http://code.google.com/apis/maps/documentation/distancematrix/

Information from URL : http://maps.googleapis.com/maps/api/distancematrix/json?origins=NG17+7LG&destinations=CV2+2DX&mode=driving&sensor=false&key=AIzaSyBQN9Dvgfw3bXpWj_-ddluungZcDv8Y4rg
matching was not perfect, returning what was found.
Error in `*tmp*`[[c(1, 1)]] : no such index at level 1
Called from: .fun(piece, ...)
Browse[1]> results <- dput(result)
list()
Browse[1]> res_df <- do.call(rbind, results)

我觉得我必须将此密钥集成到 R 上的代码中,以便 Google 获取我的权限".一位朋友告诉我,我可以通过 httr 做到这一点,但我对此知之甚少.我真的不太了解编码,我将不胜感激!

I get the feeling that I have to integrate this key on my code on R in order for Google to pick up my "permission". I got told by a friend I could do it through httr but I don't know much about it. I really don't know much about coding and I'll appreciate any help!

推荐答案

我修改了核心代码(比我之前运行的命令)如下:

I modified the core code (than I run before the commmand) as follows:

#' Compute map distances using Google
#'
#' Compute map distances using Google Maps. Note that in most cases
#' by using this function you are agreeing to the Google Maps API
#' Terms of Service at https://developers.google.com/maps/terms.
#'
#' @param from name of origin addresses in a data frame (vector
#'   accepted)
#' @param to name of destination addresses in a data frame (vector
#'   accepted)
#' @param output amount of output
#' @param mode driving, bicycling, or walking
#' @param messaging turn messaging on/off
#' @param sensor whether or not the geocoding request comes from a
#'   device with a location sensor
#' @param language language
#' @param override_limit override the current query count
#'   (.GoogleDistQueryCount)
#' @return a data frame (output="simple") or all of the geocoded
#'   information (output="all")
#' @author David Kahle \email{david.kahle@@gmail.com}
#' @details if parameters from and to are specified as geographic
#'   coordinates, they are reverse geocoded with revgeocode.  note
#'   that the google maps api limits to 2500 element queries a day.
#' @seealso
#' \url{http://code.google.com/apis/maps/documentation/distancematrix/}
#'
#' @export
#' @examples
#'
#' \dontrun{ online queries draw R CMD check times
#'
#' mapdist("waco, texas", "houston, texas")
#'
#' from <- c("houston, texas", "dallas")
#' to <- "waco, texas"
#' mapdist(from, to)
#' mapdist(from, to, mode = "bicycling")
#' mapdist(from, to, mode = "walking")
#'
#' from <- c("houston", "houston", "dallas")
#' to <- c("waco, texas", "san antonio", "houston")
#' mapdist(from, to)
#'
#'
#' # geographic coordinates are accepted as well
#' (wh <- as.numeric(geocode("the white house, dc")))
#' (lm <- as.numeric(geocode("lincoln memorial washington dc")))
#' mapdist(wh, lm, mode = "walking")
#' distQueryCheck()
#'
#' }
#'
mapdist <- function(from, to, mode = c("driving","walking","bicycling"),
  output = c("simple","all"), messaging = FALSE, sensor = FALSE,
  language = "en-EN", override_limit = FALSE, key)
{

  message("by using this function you are agreeing to the terms at :")
  message("http://code.google.com/apis/maps/documentation/distancematrix/\n")

  # check parameters
  if(is.numeric(from) && length(from) == 2) from <- revgeocode(from)
  stopifnot(is.character(from))
  if(is.numeric(to) && length(to) == 2) to <- revgeocode(to)
  stopifnot(is.character(to))
  from_to_df <- data.frame(from = from, to = to, stringsAsFactors = FALSE)
  origins <- from_to_df$from
  destinations <- from_to_df$to # this ensures # from = # to
  mode <- match.arg(mode)
  output <- match.arg(output)
  stopifnot(is.logical(messaging))
  stopifnot(is.logical(sensor))


  getdists <- function(df){

    # format url
    origin <- df$from[1]
    origin <- gsub(",", "", origin)
    origin <- gsub(" ", "+", origin)
    origin <- paste("origins=", origin, sep = "")
    destinations <- df$to
    destinations <- gsub(",", "", destinations)
    destinations <- gsub(" ", "+", destinations)
    destinations <- paste("destinations=", paste(destinations, collapse = "|"), sep = "")
    mode4url <- paste("mode=", mode, sep = "")
    lang4url <- paste("language=", language, sep = "")
    sensor4url <- paste("sensor=", tolower(as.character(sensor)), sep = "")
    keyUrl <- paste("key=", key, sep = "")
    posturl <- paste(origin, destinations, mode4url, sensor4url, keyUrl, sep = "&")
    url_string <- paste("https://maps.googleapis.com/maps/api/distancematrix/json?",
      posturl, sep = "")
    url_string <- URLencode(url_string)


    # check if query is too long
    if(nchar(url_string) >= 2048){
      n <- nrow(df)
      half_df <- floor(n/2)
      return(
        rbind(
          getdists(df[half_df,]),
          getdists(df[(half_df+1):n,])
        )
      )
    }

    # check/update google query limit
    check_dist_query_limit(url_string, elems = nrow(df),
      override = override_limit, messaging = messaging)


    # distance lookup
    if(messaging) message("trying url ", url_string)
    connect <- url(url_string)
    tree <- fromJSON(paste(readLines(connect), collapse = ""))
    close(connect)

    # message user
    message(paste0("Information from URL : ", url_string))

    # label destinations - first check if all were found
    if(length(df$to) != length(tree$destination_addresses)){
      message("matching was not perfect, returning what was found.")
      names( tree$rows[[c(1,1)]] ) <- tree$destination_addresses
      output <<- "all"
      # stringdist::amatch(df$to, tree$destination_addresses, maxDist = 10)
    } else {
      names( tree$rows[[c(1,1)]] ) <- df$to
    }

    # return
    tree$rows[[c(1,1)]]
  }

  out <- dlply(from_to_df, "from", getdists)

  # return all
  if(output == "all") return(out)



  # format output
  out <-
    ldply(out, function(oneFromList){
      ldply(oneFromList, function(oneToList){
        data.frame(
          m = oneToList$distance$value,
          km = oneToList$distance$value/1000,
          miles = 0.0006214 * oneToList$distance$value,
          seconds = oneToList$duration$value,
          minutes = oneToList$duration$value / 60,
          hours = oneToList$duration$value / 3600
        )
      })
    })

  names(out) <- c("from", "to", names(out)[3:ncol(out)])

  # "simple" return
  suppressMessages(join(from_to_df, out))
}




check_dist_query_limit <- function(url_string, elems, override, messaging){
  .GoogleDistQueryCount <- NULL; rm(.GoogleDistQueryCount); # R CMD check trick

  if(exists(".GoogleDistQueryCount", .GlobalEnv)){

    .GoogleDistQueryCount <<-
      subset(.GoogleDistQueryCount, time >= Sys.time() - 24*60*60)

    # 2500 per 24 hours
    if(sum(.GoogleDistQueryCount$elements) + elems > 2500){
      message("query max exceeded, see ?mapdist.  current total = ",
        sum(.GoogleDistQueryCount$elements))
      if(!override) stop("google query limit exceeded.", call. = FALSE)
    }

    # 100 per 10 seconds
    if(with(.GoogleDistQueryCount,
      sum(elements[time >= Sys.time() - 10]) + elems > 100
    )){
      if(messaging) message("waiting 10 seconds for another 100 queries...", appendLF=F)
      Sys.sleep(10) # can do better
      if(messaging) message(" done")
    }

    # append to .GoogleDistQueryCount
    .GoogleDistQueryCount <<- rbind(.GoogleDistQueryCount,
      data.frame(time = Sys.time(),  url = url_string,
        elements = elems, stringsAsFactors = FALSE)
    )


  } else {

    .GoogleDistQueryCount <<-
      data.frame(time = Sys.time(),  url = url_string,
        elements = elems, stringsAsFactors = FALSE)

  }
}



#' Check Google Maps Distance Matrix API query limit
#'
#' Check Google Maps Distance Matrix API query limit
#'
#' @return a data frame
#' @author David Kahle \email{david.kahle@@gmail.com}
#' @seealso \url{http://code.google.com/apis/maps/documentation/distancematrix/}
#' @export
#' @examples
#' distQueryCheck()
distQueryCheck <- function(){
  .GoogleDistQueryCount <- NULL; rm(.GoogleDistQueryCount); # R CMD check trick
  if(exists(".GoogleDistQueryCount", .GlobalEnv)){
    remaining <- 2500-sum(
      subset(.GoogleDistQueryCount, time >= Sys.time() - 24*60*60)$elements
      )
    message(remaining, " distance queries remaining.")
  } else {
    remaining <- 2500
    message(remaining, " distance queries remaining.")
  }
  invisible(remaining)
}

然后我可以通过添加键名1234"来修改 mapdist() 命令,如下所示:

Then I was able to modify the mapdist() command by adding the key name "1234" as follows:

# create your own 'from' and 'to' variables 
from <- drivetime$gp_postcode
to <- drivetime$h_postcode

    result <- vector("list")
    for (i in 1:nrow(drivetime)) { # could be 1:nrow(drivetime)
      result[[i]] <- mapdist(from[i], to[i], mode = "driving", override_limit = TRUE, key="1234") 
      Sys.sleep(0.5)
    }
    results <- dput(result)
    res_df <- do.call(rbind, results)

您可以在此处

这篇关于如何在 R 代码中集成 Google 距离矩阵 API 密钥?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆