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

R语言rvest批量请求多页面时出现HTTP error 403如何解决

问题概述
  • 开发目标:编写同站点多页面遍历爬虫,可实现两类功能之一:① 下载每个页面的HTML/CSS资源;② 提取带特定class的列表项内包含的链接,当前已完成第一类需求的基础代码
  • 技术选型:选用R语言开发,此前使用Python向该站点发起首次GET请求即返回403,因此排除BeautifulSoup、Selenium实现方案
  • 当前故障:R版代码仅能短时间正常运行,随后抛出403错误,报错信息为:Error in open.connection(x, "rb") : HTTP error 403.
  • 已考虑方案:曾计划在循环中加入Sys.sleep()设置请求间隔,但因需遍历近1000个页面,认为该方案实用性不足
  • 已知潜在解决方向:配置代理、修改请求头,但对相关技术掌握程度有限,可尝试学习落地
  • 现有参考代码:遍历存储待爬URL、对应保存文件名的dataframe逐一下载HTML,代码如下:
for (i in 1:length(data1$Search)) {
    url = data1$Search[i]
    name = data1$Name[i]
    download.file(url, destfile = paste(name, ".html", sep = ""), quiet = TRUE)
}

其中data1为包含Search、Name两列的dataframe:Search列存储待请求URL,Name列对应下载HTML文件的命名。

可行解决建议

1. 先补全合法请求头,绕过基础反爬校验

你当前使用的download.file()默认请求头特征极明显,绝大多数站点的基础反爬规则都会直接拦截这类请求,这也是短时间运行就报403的核心原因之一:

  • 弃用基础download.file(),改用httr包发起请求,手动配置和真实浏览器一致的请求头,至少要带上正常的User-Agent(打开任意网页在浏览器控制台输入navigator.userAgent就能拿到自己当前浏览器的UA,直接复制使用即可),可补充Referer字段(填写站点首页地址)、Accept字段,模拟普通用户的浏览器访问行为
  • 增加状态码判断、失败日志逻辑,遇到报错不要直接中断整个循环,把失败URL记录下来后续补爬即可
  • 修改后的参考代码:
library(httr)
# 替换成你自己浏览器的UA
my_ua <- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
# 替换成目标站点的首页地址
site_referer <- "https://替换成目标站点域名首页/"

for (i in 1:nrow(data1)) {
  url <- data1$Search[i]
  file_name <- paste0(data1$Name[i], ".html")
  # 带请求头发起GET请求,设置10秒超时
  resp <- GET(
    url = url,
    user_agent(my_ua),
    add_headers(Referer = site_referer),
    timeout(10)
  )
  # 状态码200才写入文件,否则记录失败日志
  if (status_code(resp) == 200) {
    writeBin(content(resp, "raw"), file_name)
  } else {
    cat(paste0("爬取失败|URL:", url, "|状态码:", status_code(resp), "\n"), 
        file = "crawl_fail_log.txt", 
        append = TRUE)
  }
}

2. 搭配随机短间隔+重试逻辑,成本极低

完全没必要因为要爬1000个页面就放弃间隔设置:

  • 不要用固定长间隔,改成0.5-2秒的随机短间隔即可,每次请求完执行Sys.sleep(runif(1, 0.5, 2)),爬完1000个页面总耗时仅十几分钟,远低于触发403后等待IP解封、重新排查问题的时间成本
  • 增加简单重试逻辑:遇到403状态码时,等待5-10秒后重新发起请求,重试2-3次仍失败再记入日志,绝大多数临时触发的频率限制都能通过这个方式绕过

3. 代理IP配置方案(上述方案无效时再使用)

如果补全请求头、加了随机间隔仍然短时间触发403,说明站点做了IP维度的频率限制:

  • 准备可用的代理IP资源,在httr的GET请求中加入use_proxy()参数即可,格式为use_proxy("代理IP地址", 端口, username = "认证用户名(若有)", password = "认证密码(若有)")
  • 每爬取30-50页切换一次代理IP,避免单个IP请求频率过高被封禁

4. 第二类提取需求的适配方法

后续如果要切换为“提取特定class列表项内链接”的功能,不需要把所有HTML都下载到本地,直接用rvest包解析请求返回的响应内容即可,参考逻辑:

library(rvest)
# 解析响应内容为HTML结构
page_doc <- read_html(resp)
# 替换成你要定位的class名称
target_links <- page_doc %>% 
  html_elements(".替换成目标class名") %>% 
  html_element("a") %>% 
  html_attr("href")
# 将提取到的相对路径链接转为绝对路径
target_links <- url_absolute(target_links, url)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 11:15:41