无法向R函数传入eventid列表?如何批量调用API生成tibble
批量调用API并合并结果的解决方案
已知目标API仅支持单次传入一个eventId,单个调用函数可正常返回数据,但批量传入ID列表时出现错误,需实现批量调用并将所有响应结果合并为一个tibble。
原函数代码
my_func <- function(sport, eventId = eventids, apiKey = "xxxxxxxxxxxxxxxxxxxxxxxxxx", regions = "us", markets = "alternate_spreads", odds_format = "american", date_format = "iso"){ base_url = glue::glue("https://xxx.xxx-xxx-xxx.xxx/xx/xxxxxx/{sport}/xxxxxx/{eventId}/odds") query_params <- list(apiKey = apiKey, sport = sport, eventId = eventId, regions = regions, markets = markets, oddsFormat = odds_format, dateFormat = date_format) endpoint <- httr::modify_url(base_url, query = query_params) resp <- fromJSON(endpoint) %>% as_tibble(validate = F) %>% unnest(cols = bookmakers) %>% rename("bookmaker_key" = "key") %>% unnest(cols = markets) %>% unnest(cols = outcomes) return(resp) }
尝试过的方法及对应错误
传入tibble格式的ID列表:
eventids <- tibble(id = c("xxxxxxxxxxxxxx57adaf06d2660af34", "xxxxxxxxxxx7aa5a4bce731a0")) my_func('basketball')错误信息:
Error in open.connection(con, "rb") : cannot open the connection to 'https://xxx.xxx-xxxx-xx/sports/basketball/events/truncated? In addition: Warning message: In open.connection(con, "rb") : cannot open URL 'https://xxx.xxx-xxxx-xx/sports/basketball/events/truncated? HTTP status was '422 Unknown Error'传入向量格式的ID列表:
eventids <- c("xxxxxxxxxxxxxx57adaf06d2660af34", "xxxxxxxxxxx7aa5a4bce731a0") my_func('basketball')错误信息:
Error in parse_url(url) : length(url) == 1 is not TRUE用
paste拼接ID字符串:eventids1 = paste(eventids, collapse = ",") my_func('basketball', eventId = eventids1)仍触发上述
parse_url错误。用
purrr::map批量调用:map(eventids, my_func) # 或 map(eventids, ~my_func(sport = "basketball", eventId = .x))错误信息:
Error in `map()`: ℹ In index: 1. ℹ With name: id. Caused by error in `parse_url()`: ! length(url) == 1 is not TRUE
解决方案
步骤1:修正函数,确保仅处理单个eventId
原函数在生成base_url时,若传入多个ID会生成多段URL,导致后续httr::modify_url报错。需强制函数仅接收单个ID,并添加参数校验:
my_func <- function(sport, eventId, # 移除默认值,强制传入单个ID apiKey = "xxxxxxxxxxxxxxxxxxxxxxxxxx", regions = "us", markets = "alternate_spreads", odds_format = "american", date_format = "iso"){ # 校验eventId为单个字符串 if(length(eventId) != 1) stop("eventId must be a single character string") base_url = glue::glue("https://xxx.xxx-xxx-xxx.xxx/xx/xxxxxx/{sport}/xxxxxx/{eventId}/odds") query_params <- list(apiKey = apiKey, sport = sport, eventId = eventId, regions = regions, markets = markets, oddsFormat = odds_format, dateFormat = date_format) endpoint <- httr::modify_url(base_url, query = query_params) # 明确指定包名,避免命名冲突 resp <- jsonlite::fromJSON(endpoint) %>% dplyr::as_tibble(validate = F) %>% tidyr::unnest(cols = bookmakers) %>% dplyr::rename("bookmaker_key" = "key") %>% tidyr::unnest(cols = markets) %>% tidyr::unnest(cols = outcomes) return(resp) }
步骤2:用purrr::map_dfr批量调用并合并结果
map_dfr会自动将每个API调用的结果行绑定为一个tibble:
# 若eventids是tibble,先提取ID向量 event_ids_vec <- eventids$id # 批量调用并合并结果 final_result <- purrr::map_dfr(event_ids_vec, ~my_func(sport = "basketball", eventId = .x))
可选:添加错误容错机制
若部分eventId可能无效,用purrr::possibly包裹函数,避免单个ID调用失败导致整个批量任务中断:
# 创建容错版函数,调用失败时返回空tibble safe_my_func <- purrr::possibly(my_func, otherwise = dplyr::tibble()) # 批量调用 final_result <- purrr::map_dfr(event_ids_vec, ~safe_my_func(sport = "basketball", eventId = .x))
内容的提问来源于stack exchange,提问作者Aaron Morris
相关产品推荐
相关产品推荐

