R语言httr包POST请求下载网站zip文件失效问题
R语言批量下载TranStats平台航空数据zip包实现方案
失效原因
TranStats航空数据下载页基于ASP.NET Web Forms框架开发,所有触发下载的POST请求必须携带当前访问会话实时生成的动态校验参数才能通过服务端校验:
__VIEWSTATE:加密存储页面控件状态的视图状态参数__VIEWSTATEGENERATOR:视图状态生成标识__EVENTVALIDATION:用于防伪造请求的事件校验参数
旧流程直接复制浏览器单次请求的cURL转R代码,本质是硬编码了单次请求生成的校验参数,和后续请求的会话Cookie不匹配,会被服务端拦截,返回HTML页面而非目标zip压缩包,因此执行后无法得到有效文件。
实现代码
核心逻辑是先建立HTTP会话访问下载页,从返回的页面源码中提取当前会话对应的3个动态校验参数,再和自定义的年份、月份、字段选择参数拼接后提交POST请求,直接将返回的二进制内容写入本地zip文件即可。
依赖包安装命令:
install.packages(c("httr", "rvest"))
完整可运行代码:
library(httr) library(rvest) # 下载配置项,按需修改 target_page <- "https://www.transtats.bts.gov/DL_SelectFields.aspx?gnoyr_VQ=FIL&QO_fu146_anzr=Nv4%20Pn44vr45" local_save_path <- "bts_airline_data.zip" download_year <- "2023" download_month <- "All" # 填"All"下载全年12个月数据,填单个数字如"1"对应1月 # 需下载的字段列表,可根据实际需求增删 selected_fields <- c( "FL_DATE", "OP_CARRIER", "OP_CARRIER_FL_NUM", "ORIGIN", "DEST", "CRS_DEP_TIME", "DEP_TIME", "DEP_DELAY", "CRS_ARR_TIME", "ARR_TIME", "ARR_DELAY", "CANCELLED", "CANCELLATION_CODE", "AIR_TIME", "DISTANCE" ) # 步骤1:建立会话,访问页面获取动态校验参数 base_resp <- GET( url = target_page, user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36") ) page_parsed <- read_html(base_resp) # 提取当前会话的3个ASP.NET校验参数 vs <- page_parsed |> html_element("#__VIEWSTATE") |> html_attr("value") vsg <- page_parsed |> html_element("#__VIEWSTATEGENERATOR") |> html_attr("value") ev <- page_parsed |> html_element("#__EVENTVALIDATION") |> html_attr("value") # 步骤2:构造POST请求体 req_body <- list( `__EVENTTARGET` = "", `__EVENTARGUMENT` = "", `__VIEWSTATE` = vs, `__VIEWSTATEGENERATOR` = vsg, `__EVENTVALIDATION` = ev, `btnDownload` = "Download" ) # 拼接年份参数 req_body[[paste0("cboYear", download_year)]] <- download_year # 拼接月份参数 if (download_month == "All") { req_body[["cboMonthAll"]] <- "All" } else { req_body[["cboMonth"]] <- as.character(download_month) } # 拼接选中字段参数 for (f in selected_fields) { req_body[[f]] <- "on" } # 步骤3:提交下载请求 download_resp <- POST( url = target_page, handle = handle(base_resp), # 复用会话Cookie,保证参数和会话匹配 user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"), body = req_body, encode = "form" ) # 校验返回结果并写入文件 if (http_type(download_resp) == "application/x-zip-compressed") { writeBin(content(download_resp, as = "raw"), local_save_path) cat("下载完成,文件保存路径:", normalizePath(local_save_path), "\n") } else { warning("请求未返回zip文件,返回内容类型:", http_type(download_resp)) }
使用说明
- 禁止硬编码
__VIEWSTATE、__EVENTVALIDATION参数,两个参数每次访问页面都会重新生成,必须和同一会话的Cookie绑定才能通过校验 - 批量下载多年/多月数据时,每次发起下载请求前都需要重新执行「访问页面-提取动态参数」步骤,避免参数过期失效
- 单次请求不要选择过大时间范围或过多字段,服务端存在请求超时限制,跨度超过3年的数据建议拆分多次下载
- 若请求失败,可运行
cat(content(download_resp, as = "text"))查看返回的页面提示,一般为会话超时、参数缺失导致,重新运行步骤1获取新参数即可
内容的提问来源于stack exchange,提问作者FilipeTeixeira
相关产品推荐
相关产品推荐

