导读:本期聚焦于小伙伴创作的《如何用R语言抓取气象局历史天气数据并解析API完成本地归档》,敬请观看详情。直接调用气象局开放接口获取历史天气记录时,不少人卡在返回字段结构和分页逻辑上。本文用R语言演示如何构造带鉴权参数的请求,解析JSON中的温度、降水与风速字段,并把逐日数据落盘为本地CSV与SQLite库。对比手动下载与脚本抓取的耗时差异后,重点说明时区转换、缺失值填补和增量更新三种归档策略,帮你在合规前提下建立可复用的气象数据集。

在气象分析与建模工作中,获取长期历史天气记录是常见需求。气象局网站通常提供了标准化的数据接口,通过R语言编写脚本可以稳定地拉取指定站点、指定日期范围内的观测值,并将结果有序地保存到本地。本文围绕接口调用、字段解析与归档设计三个层面,说明一套可落地的实现方案。

如何用R语言抓取气象局历史天气数据并解析API完成本地归档

气象局API的请求构造与鉴权

大多数气象局开放平台要求先申请开发者令牌,然后在每次请求中携带令牌与签名参数。以某省级气象数据接口为例,基础地址为 https://api.ipipp.com/weather/history,需要传入station_idstart_dateend_datetoken。R语言中可以使用httr包组装查询,注意日期格式必须严格为YYYYMMDD,否则会返回空数据集。

除了令牌,部分接口还使用时间戳与随机串防止重放攻击。我们可以在脚本里用Sys.time()生成时间戳,再拼接待签名原文做MD5。下面示例展示如何构造带鉴权头的GET请求,并处理可能的限流返回码。当收到429时,应当暂停数秒再重试,而不是频繁发起调用,以免被封禁IP。

library(httr)
library(digest)

base_url <- "https://api.ipipp.com/weather/history"
token <- "your_token_here"
station <- "54511"
start <- "20230101"
end <- "20230131"
ts <- as.character(as.integer(Sys.time()))
nonce <- sample(letters, 8, replace = TRUE) |> paste(collapse = "")
sign <- digest(paste0(token, ts, nonce), algo = "md5")

resp <- GET(base_url, query = list(
  station_id = station,
  start_date = start,
  end_date = end,
  token = token,
  timestamp = ts,
  nonce = nonce,
  sign = sign
))

if (status_code(resp) == 200) {
  data <- content(resp, "parsed")
} else if (status_code(resp) == 429) {
  Sys.sleep(5)
}

上述代码把鉴权逻辑封装在请求前,实际工程中建议将令牌与签名函数独立成模块,便于多任务复用。同时要注意,气象局接口常按日或按旬分页,若一次拉取整年数据可能触发长度限制,需要循环切分时间窗。

返回JSON的字段解析与清洗

接口一般返回JSON数组,每条记录包含观测时间、平均气温、最高最低温、降水量与风速等。R里用jsonlite包的fromJSON可直接转成数据框,但原始字段名常为英文缩写,需要重命名为业务易懂的列。例如t_avg改为avg_temppre改为precipitation

真实数据里经常遇到缺失观测,接口可能返回null或空字符串。若不处理,后续写入数据库会报错。可以用na_if把空串转成NA,再根据相邻日期线性插补。下面代码演示解析并填补缺失气温的过程,同时把字符型日期转为Date类型,方便按时间排序。

library(jsonlite)
library(dplyr)

raw <- fromJSON(toJSON(data$list))
df <- raw |>
  transmute(
    obs_date = as.Date(date, "%Y-%m-%d"),
    avg_temp = na_if(t_avg, ""),
    max_temp = na_if(t_max, ""),
    min_temp = na_if(t_min, ""),
    precipitation = na_if(pre, ""),
    wind_speed = na_if(ws, "")
  )

df <- df |>
  mutate(across(where(is.character), as.numeric)) |>
  arrange(obs_date) |>
  mutate(avg_temp = approx(obs_date, avg_temp, obs_date)$y)

清洗后的数据框应当做基础校验,比如气温是否在合理区间、降水非负。发现异常值可用clip截断或标记为疑误。这一步保证了归档数据质量,避免污染分析模型。另外,气象局时间多为北京时间,若本地环境时区不同,需用with_tz显式声明,防止日期错位。

本地归档策略与增量更新

数据落盘可选CSV或SQLite。CSV适合一次性导出给非技术同事,但频繁追加会产生重复头。SQLite则支持表结构约束与索引,更适合长期累积。使用RSQLite包可建立连接,用dbWriteTable以追加模式写入,并通过唯一索引避免重复插入同一天记录。

增量更新是归档系统的核心。我们可以记录上次抓取的最大日期,下次只请求该日期之后的值。这样既能减少接口压力,也能应对气象局后期修订历史数据的情况。下面示例展示如何比对库中已有日期并构造补数区间,同时把每日抓取日志写入独立表,方便排查断点。

library(RSQLite)

con <- dbConnect(SQLite(), "weather_archive.db")
existing <- dbGetQuery(con, "SELECT max(obs_date) AS mx FROM weather")
last_day <- if (is.na(existing$mx)) as.Date("2000-01-01") else existing$mx

new_start <- format(last_day + 1, "%Y%m%d")
new_end <- format(Sys.Date() - 1, "%Y%m%d")

if (new_start <= new_end) {
  # 此处调用前文请求与解析函数获取 fresh_df
  dbWriteTable(con, "weather", fresh_df, append = TRUE)
  dbExecute(con, "CREATE UNIQUE INDEX IF NOT EXISTS idx_day ON weather(obs_date)")
}
dbDisconnect(con)

归档完成后,建议定期做完整性检查:统计每年天数是否接近365、关键站点是否连续无空洞。若发现某月缺失,可手动触发补抓任务。对于多站点场景,应为每个station_id建立分区视图,查询时按站点过滤,能够显著提升读取效率并降低单表膨胀风险。

R语言气象局API数据归档修改时间:2026-08-14 04:48:29

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。