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

R语言按日期序列循环爬取网页表格并存储的问题求助

R批量爬取日期维度数据修复方案

你原代码跑不通的核心原因有三个:一是请求体里的vfecha参数写死了固定日期,完全没关联你预设的fechas日期序列;二是文件名生成逻辑写的timestamp <- 1:seq_along(i)是无意义的动态序列,既没绑定索引也没绑定日期;三是没有容错和请求间隔,很容易跑一半中断或者被服务器拦截。

修正后完整代码

# 加载依赖
library(httr)
library(rvest)
library(janitor)
library(dplyr)
library(purrr)

# 固定配置项
headers <- c("Content-Type" = "application/x-www-form-urlencoded; charset=UTF-8")
target_url <- "http://old.emmsa.com.pe/emmsa_spv/app/reportes/ajax/rpt07_gettable.php"
# 替换成你自己的存储路径,注意路径末尾要加/
save_dir <- "c:/Users/.../Desktop/data/"
# 自动创建不存在的存储目录,避免存文件时报路径错误
dir.create(save_dir, recursive = TRUE, showWarnings = FALSE)

# 第一步:生成符合接口格式要求的日期序列
# 接口要求vfecha格式为「日/月/年」,例如22/06/2022
# 下面示例是生成2022年6月全月的日期,替换起止日期为你需要的范围即可
fechas <- seq.Date(
  from = as.Date("2022-06-01"),
  to = as.Date("2022-06-30"),
  by = "day"
) |> format("%d/%m/%Y")

# 第二步:map方式批量爬取(你需要的map循环写法)
# walk函数专门处理存文件这类无返回值的副作用操作,比普通map更适配
walk(fechas, function(current_date){
  # 动态拼接当前日期对应的请求体
  req_body <- paste0("vid_tipo=1&vprod=&vvari=&vfecha=", current_date)
  
  # 发请求,内置3次失败自动重试,避免网络波动中断任务
  resp <- RETRY(
    verb = "POST",
    url = target_url,
    add_headers(.headers = headers),
    body = req_body,
    times = 3
  )
  
  # 解析页面表格
  precios <- resp |> 
    content() |> 
    html_element(".timecard") |> 
    html_table() |> 
    row_to_names(1) |> 
    clean_names() |> 
    filter(producto != "") |> 
    # 用across替代已过时的mutate_at,长期兼容性更好
    mutate(across(matches("precio"), as.numeric)) |> 
    as_tibble()
  
  # 生成符合命名要求的文件名:把日期里的/替换成-,适配Windows文件命名规则
  file_suffix <- gsub("/", "-", current_date)
  save_path <- paste0(save_dir, "data_", file_suffix, ".rds")
  
  # 保存文件
  saveRDS(precios, file = save_path)
  
  # 打印进度,方便看跑到哪了
  cat("完成爬取:", current_date, " 保存路径:", save_path, "\n")
  
  # 加1秒请求间隔,避免请求太频繁触发反爬
  Sys.sleep(1)
})

# 如果习惯用基础for循环,用下面这段替换上面的walk部分即可
# for (current_date in fechas) {
#   req_body <- paste0("vid_tipo=1&vprod=&vvari=&vfecha=", current_date)
#   resp <- RETRY("POST", target_url, add_headers(.headers = headers), body = req_body, times = 3)
#   precios <- content(resp) |> html_element(".timecard") |> html_table() |> row_to_names(1) |> clean_names() |> filter(producto != "") |> mutate(across(matches("precio"), as.numeric)) |> as_tibble()
#   file_suffix <- gsub("/", "-", current_date)
#   save_path <- paste0(save_dir, "data_", file_suffix, ".rds")
#   saveRDS(precios, file = save_path)
#   cat("完成爬取:", current_date, "\n")
#   Sys.sleep(1)
# }

对应问题说明

  • 按日期序列爬取问题:每次循环都会动态把当前日期拼接到请求体的vfecha参数上,每个日期对应一次独立请求,不会再重复爬取固定日期的数据
  • 文件名嵌入日期问题:爬取到的日期是22/06/2022格式,把斜杠替换为横杠(Windows系统文件名不允许出现/字符)后直接拼接到文件名中,就能生成你需要的data_22-06-2022.rds格式
  • 请求参数绑定问题:没有用固定写死的请求体字符串,每次循环实时拼接当前日期到vfecha参数位,和日期序列一一对应
  • 爬取与存储优化建议:
    • 用httr::RETRY替代原生POST,遇到网络波动、服务器临时5xx错误会自动重试3次,不会因为单次请求失败中断整个批量任务
    • 加1秒请求间隔,避免高频请求触发服务器反爬拦截
    • 开头加了自动创建存储目录的代码,不用手动提前建文件夹,避免路径不存在报错
    • 用across替代已经进入生命周期末期的mutate_at,后续dplyr版本升级不会出现函数弃用警告
    • 如果后续需要做全量数据分析,可以在爬取时把每个日期的结果存在同一个列表里,最后用bind_rows()合并成一张总表,额外存一份总rds文件,不用后续逐个读取拼接

内容的提问来源于stack exchange,提问作者Carlos Garibotto

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 11:36:16