如何在R中通过GraphQL调用API时循环遍历监测点ID获取数据
问题排查与修正方案
核心问题分析
你的循环代码存在几个关键错误,导致返回空数据:
- 循环对象错误:
my_list1 <- list(res3_data$id)将整个ID列包装成了单个列表元素,循环仅执行一次,且i是完整的ID向量而非单个监测点ID。 - 查询字符串未动态插值:GraphQL查询中
trafficRegistrationPointId: "i"是固定字符串"i",没有替换为循环变量的实际ID值,导致查询不存在的监测点。 - ID赋值错误:
ids$PointId <- "i"赋值的是字符串"i",而非当前循环的监测点ID。 - 结果合并效率低且易出错:使用
rbind逐次合并数据框,初始空data.frame会在空结果返回时引发结构异常。
修正后的完整代码
# 安装并加载所需包 install.packages(c("ghql", "httr", "glue")) library(tidyr) library(httr) library(ghql) library(jsonlite) library(dplyr) library(glue) # 初始化GraphQL连接 link <- 'https://www.vegvesen.no/trafikkdata/API/' conn <- GraphqlClient$new(url = link) # ---------------------- # 步骤1:获取监测点ID列表 # ---------------------- qry <- Query$new() qry$query('z', '{ trafficRegistrationPoints(searchQuery: { roadCategoryIds: [E] }) { id name location { coordinates { latLon { lat lon } } } } }') res3 <- conn$exec(qry$queries$z) res3 <- jsonlite::fromJSON(res3, flatten = TRUE) res3_data <- res3$data$trafficRegistrationPoints %>% as_tibble() # 直接提取ID向量作为循环对象(无需包装成list) id_list <- res3_data$id # ---------------------- # 步骤2:批量获取监测点数据 # ---------------------- # 用列表收集结果(比rbind更高效) results_list <- list() for (i in id_list) { # 避免请求频率过高 Sys.sleep(1) # 动态生成GraphQL查询(用glue插入当前ID) query_str <- glue('{{ trafficData(trafficRegistrationPointId: "{i}") {{ volume {{ byHour( from: "2022-05-01T00:00:00+02:00" to: "2022-05-04T23:00:00+02:00" ) {{ edges {{ node {{ from to total {{ volumeNumbers {{ volume }} coverage {{ percentage }} }} }} }} }} }} }} }}') # 执行查询 qry <- Query$new() qry$query('x', query_str) res <- conn$exec(qry$queries$x) res <- jsonlite::fromJSON(res, flatten = TRUE) # 检查是否返回有效数据,避免空值报错 if (!is.null(res$data$trafficData)) { ids_data <- res$data$trafficData$volume$byHour$edges %>% as_tibble() ids_data$PointId <- i # 赋值当前监测点ID results_list[[i]] <- ids_data } else { message(paste("监测点", i, "无数据,跳过")) } } # 合并所有结果为单个数据框 all_ids <- bind_rows(results_list) # 查看合并后的数据 head(all_ids)
关键优化点
- 使用
glue包实现GraphQL查询的动态变量插值,确保每个请求使用正确的监测点ID。 - 用列表收集结果后一次性合并,提升批量处理的效率。
- 添加空值检查,跳过无数据的监测点,避免循环中断。
- 直接使用ID向量作为循环对象,确保每次循环处理单个监测点。
内容的提问来源于stack exchange,提问作者olesrumbleinthejungle
相关产品推荐
相关产品推荐

