You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在R中通过GraphQL调用API时循环遍历监测点ID获取数据

问题排查与修正方案

核心问题分析

你的循环代码存在几个关键错误,导致返回空数据:

  1. 循环对象错误:my_list1 <- list(res3_data$id)将整个ID列包装成了单个列表元素,循环仅执行一次,且i是完整的ID向量而非单个监测点ID。
  2. 查询字符串未动态插值:GraphQL查询中trafficRegistrationPointId: "i"是固定字符串"i",没有替换为循环变量的实际ID值,导致查询不存在的监测点。
  3. ID赋值错误:ids$PointId <- "i"赋值的是字符串"i",而非当前循环的监测点ID。
  4. 结果合并效率低且易出错:使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 15:43:21