如何用httr::POST批量获取REDCap调查链接?
批量调用REDCap API获取调查链接报错的解决方法
问题描述
作为R语言新手,使用httr::POST调用REDCap API获取单个调查链接的代码可正常运行,但尝试通过循环批量获取多个record对应的链接时出现错误:
Error in vapply(elements, encode, character(1)) : values must be length 1, but FUN(X[[6]]) result is length 2
错误源于POST请求的参数编码,调用栈如下:
6. vapply(elements, encode, character(1)) 5. compose_query(body) 4. body_raw(compose_query(body), "application/x-www-form-urlencoded") 3. body_config(body, match.arg(encode)) 2. request_build("POST", hu$url, body_config(body, match.arg(encode)), as.request(config), ...) 1. httr::POST(url, body = formData, encode = "form")
原单次请求代码:
token <- "FC9439DCA5A64714XXXXXXXXXXXXX" url <- "https://redcap.fmrp.usp.br/api/" formData <- list("token"=token, content='surveyLink', format='xml', instrument= "qualidade_de_vida_cervical", event= "baseline_arm_1", record= "1", returnFormat='xml' ) response <- httr::POST(url, body = formData, encode = "form") result <- httr::content(response) result <- minimal_html(result) %>% html_elements("body") %>% html_text2() return(result)
尝试的批量代码(报错):
my_list <- c("949_1","949_2") for (i in my_list){ token <- "FC9439DCA5A64XXXXXXXXXXXXXXXX" url <- "https://redcap.fmrp.usp.br/api/" formData <- list("token"=token, content='surveyLink', format='xml', instrument= "qualidade_de_vida_cervical", event= "baseline_arm_1", record= my_list, returnFormat='xml' ) response <- httr::POST(url, body = formData, encode = "form") result <- httr::content(response) result <- minimal_html(result) %>% html_elements("body") %>% html_text2() return(result) }
错误原因
你在循环里犯了两个关键错误:
record参数赋值错误:循环中你把整个my_list传给了record,而非当前迭代的元素i,导致record是长度为2的向量。REDCap的surveyLink接口单次请求仅接受单个record值,同时httr的encode="form"要求每个参数都是长度1的元素,这直接触发了编码错误。- 循环内过早使用
return():return()会直接终止循环和函数运行,第一次迭代就会退出,根本不会处理第二个record。
解决方案
可以通过修正循环或使用迭代函数两种方式实现批量获取,具体如下:
方法1:修正for循环
library(httr) library(rvest) token <- "FC9439DCA5A64XXXXXXXXXXXXXXXX" url <- "https://redcap.fmrp.usp.br/api/" my_list <- c("949_1","949_2") survey_links <- character(length(my_list)) # 预先创建存储结果的向量 for (i in seq_along(my_list)) { current_record <- my_list[i] formData <- list( "token" = token, content = 'surveyLink', format = 'xml', instrument = "qualidade_de_vida_cervical", event = "baseline_arm_1", record = current_record, returnFormat = 'xml' ) response <- httr::POST(url, body = formData, encode = "form") result <- httr::content(response) survey_links[i] <- minimal_html(result) %>% html_elements("body") %>% html_text2() } # 查看结果 survey_links
方法2:使用purrr迭代函数
如果习惯函数式编程,用purrr::map()更简洁:
library(httr) library(rvest) library(purrr) token <- "FC9439DCA5A64XXXXXXXXXXXXXXXX" url <- "https://redcap.fmrp.usp.br/api/" my_list <- c("949_1","949_2") get_survey_link <- function(record_id) { formData <- list( "token" = token, content = 'surveyLink', format = 'xml', instrument = "qualidade_de_vida_cervical", event = "baseline_arm_1", record = record_id, returnFormat = 'xml' ) response <- httr::POST(url, body = formData, encode = "form") result <- httr::content(response) minimal_html(result) %>% html_elements("body") %>% html_text2() } # 批量获取链接 survey_links <- map_chr(my_list, get_survey_link) # 查看结果 survey_links
注意事项
- 确保REDCap项目权限允许批量获取调查链接,部分项目可能限制接口调用频率,若遇到限流问题,可在循环中加入
Sys.sleep(1)之类的延迟。 - 始终保护
token的安全性,不要将明文token提交到代码仓库或公开场合。
内容的提问来源于stack exchange,提问作者Gabriel Pokorny
相关产品推荐
相关产品推荐

