如何让R循环遇502错误时重试下载Google Earth KMZ文件
解决方案
核心优化点
- 增加错误捕获与重试机制:用
tryCatch包裹易失败的HTTP请求操作,遇到502等错误时自动重试,直到成功 - 替换不稳定的
browseURL:改用httr::GET直接下载文件,避免依赖浏览器,同时能更精准控制请求和错误处理 - 移除固定等待时间:根据下载状态动态判断,而非固定
Sys.sleep(10) - 简化文件命名逻辑:直接指定下载路径和文件名,无需读取下载文件夹快照
修改后的完整代码
首先需要安装并加载httr包(比原生readLines更适合HTTP请求处理):
loadandinstall <- function(mypkg) { if (!is.element(mypkg, installed.packages()[,1])){ install.packages(mypkg, repos="http://cran.r-project.org") } library(mypkg, character.only=TRUE) } # 加载所需包,新增httr用于稳定HTTP请求 loadandinstall("stringr") loadandinstall("rvest") loadandinstall("XML") loadandinstall("maptools") loadandinstall("rgeos") loadandinstall("rgdal") loadandinstall("foreign") loadandinstall("raster") loadandinstall("sp") loadandinstall("parallel") loadandinstall("snow") loadandinstall("httr") # 读取CSV数据(优化:只读取一次,避免重复IO) data <- read.csv(str_c(basedir,"AllPlantingLocationData_WebsiteSource_2019.csv"), header=TRUE, colClasses=rep("character", 3)) urlstring <- data[,1] gurls <- data[,2] names <- data[,3] # 定义重试函数:用于包裹易失败的操作 retry_on_error <- function(expr, max_tries = Inf, wait_seconds = 5) { tries <- 0 repeat { tries <- tries + 1 result <- tryCatch({ expr TRUE # 操作成功返回TRUE }, error = function(e) { # 打印错误信息和重试次数 cat(sprintf("请求失败(第%d次重试):%s\n", tries, e$message)) Sys.sleep(wait_seconds) FALSE # 失败返回FALSE }) if (result || tries >= max_tries) break } } # 循环处理每个URL for(i in 1:length(urlstring)){ cat(sprintf("开始处理第%d个URL:%s\n", i, urlstring[i])) # 1. 获取网页源码(带重试) success <- retry_on_error({ # 用httr::GET替代readLines,更稳定的HTTP请求 response <- GET(urlstring[i]) stop_for_status(response) # 自动检查HTTP状态码,非200则抛出错误 t <- as.list(content(response, "text", encoding = "UTF-8")) t <- str_split(t, "\n")[[1]] # 按行分割成列表,模拟原readLines行为 }) if(!success) { cat(sprintf("第%d个URL多次重试仍失败,跳过(可后续手动处理)\n", i)) next } # 2. 提取Google Maps URL(原逻辑保留) m <- unlist(t[which(!is.na(str_locate(t,"<iframe src=")[,1]))]) gurl <- unlist(strsplit(substring(str_c(m),14,nchar(m))," "))[1] gurl <- substring(gurl,1,nchar(gurl)-1) gurls[i] <- str_c(gsub("embed","kml",gurl)) # 3. 下载KMZ文件(带重试,直接指定路径) download_path <- file.path("/Users/badiskhiari/Downloads", paste0(names[i], ".kmz")) success <- retry_on_error({ response <- GET(gurls[i], write_disk(download_path, overwrite = TRUE)) stop_for_status(response) }) if(success) { print(str_c("URL ",i," 下载完成!!")) } else { cat(sprintf("第%d个URL的KMZ文件多次重试仍下载失败\n", i)) } }
关键代码解释
retry_on_error函数:封装了重试逻辑,传入要执行的表达式,失败后等待指定时间重试,直到成功或达到最大次数(这里设为无限,可根据需求调整max_tries)httr::GET替代原生方法:- 能自动处理HTTP状态码,
stop_for_status会在状态码非200(如502)时抛出错误,触发重试 write_disk直接将响应内容写入指定文件,无需依赖浏览器和下载文件夹快照
- 能自动处理HTTP状态码,
- 单次CSV读取:原代码重复读取3次CSV,优化为只读一次,提升效率
- 错误日志输出:每次失败都会打印错误信息和重试次数,方便排查问题
额外建议
- 可以调整
wait_seconds参数,比如失败后等待时间逐渐增加(如5秒→10秒→15秒),避免频繁请求给服务器造成压力 - 如果部分URL确实无法访问,可记录这些URL到单独文件,后续手动处理
- 考虑加入并行处理(原代码加载了
parallel和snow),但需注意不要同时发起过多请求导致被服务器封禁
内容的提问来源于stack exchange,提问作者badiskhiari
相关产品推荐
相关产品推荐

