R语言批量下载URL多文件:跳过空链接与存储路径配置问题
R爬取欧洲议会书面质询文档解决方案
现有代码的核心问题修复
你写的测试代码有两个直接导致故障的错误:
purrr::safely()用法错误:safely的作用是封装函数生成容错版本,不是把函数执行语句直接放到safely括号里。你当前的写法是直接在括号内执行download.file,根本没有做异常捕获,遇到404、连接超时自然会直接终止程序。destfile路径拼接错误:你写的路径"/Users/...[i]"把[i]当成了固定字符串内容,没有做变量拼接,除了第一次循环可能碰巧路径有效,后续循环的存储路径全是无效值,自然会出现存储结果为NA的问题。另外下载docx这类二进制文件要加mode = "wb"参数,否则Windows环境下下载的文件会损坏。
修正后的可运行基础测试代码如下:
library(purrr) # 基础路径配置 base.url <- "https://www.europarl.europa.eu/doceo/document/" doc_prefix <- "P-9-2022-00" doc_suffix <- "_EN.docx" # 替换为你本地的实际存储根路径 local_root <- "/Users/yourname/europarl_docs/2022/" # 待遍历的文档编号区间 doc_numbers <- 2330:2333 # 封装带容错、断点续传逻辑的安全下载函数 safe_download <- safely(function(doc_id){ # 拼接远程文件URL remote_file <- paste0(base.url, doc_prefix, doc_id, doc_suffix) # 拼接本地存储路径 local_file <- paste0(local_root, doc_id, doc_suffix) # 本地已存在对应文件时直接跳过,避免重复请求 if(file.exists(local_file)) return(paste("Skip existing:", doc_id)) # 执行下载,设置10秒超时避免程序卡滞,二进制模式写入保证文件完整 download.file(remote_file, destfile = local_file, timeout = 10, mode = "wb") return(paste("Download success:", doc_id)) }) # 批量遍历执行 walk(doc_numbers, function(id){ result <- safe_download(id) # 打印执行日志,出错不中断循环 if(!is.null(result$error)){ cat("Download failed, doc ID:", id, "Error:", result$error$message, "\n") }else{ cat(result$result, "\n") } })
非连续编号爬取的容错配置
针对文档编号不连续、无效编号多的问题,在上述代码基础上补充几个配置即可稳定运行:
- 所有下载请求都会被safely捕获异常,404、连接重置、超时等问题都不会中断整体循环,只会打印错误日志
- 可以在下载前加
httr::HEAD()请求先判断链接状态,返回状态码200再执行下载,比直接下载无效链接节省流量和时间 - 每次请求后加0.5-2秒的随机延迟,避免请求频率过高被站点封禁IP
12万份文档的存储与任务管理方案
你提出的按15个年份分批次运行的思路完全可行,补充几个优化点降低运维成本:
- 本地存储目录按年份建子文件夹,不要把12万个文件全部放在同一目录下,否则文件系统加载、检索都会非常卡顿
- 保留代码里的本地文件存在即跳过的逻辑,天然支持断点续传,就算中途断网、程序崩溃,下次启动后会自动从上次中断的位置继续爬取,不需要手动记录进度
- 单独维护一份CSV格式的爬取日志,记录每个文档编号的爬取状态(成功/失败)、失败原因、爬取时间,最后爬完可以单独对失败的条目做补爬,不用重新跑全量任务
- 不要尝试把所有docx文件读入R内存存成R对象,12万份文档体积会达到几十上百GB,内存根本承载不了,直接按原格式分类存在本地磁盘即可,后续做文本分析时再批量读取处理。
爬取效率优化建议
遍历编号的思路可以跑通,但如果无效编号占比高会浪费大量请求时间,可以做个优化:
- 欧洲议会的书面质询文档编号是按「议会届数-年份-流水号」规则生成的,可以先对应好每届议会的任职时间范围,缩小每个年份对应的流水号遍历区间,减少无效请求
- 站点本身公开了所有书面质询的元数据索引,你可以在站点的公开数据板块找到全量有效文档的编号列表,拿到有效编号后再批量下载,比盲猜遍历号段的效率高2-3倍,也不用处理大量404请求。
内容的提问来源于stack exchange,提问作者kari9328
相关产品推荐
相关产品推荐

