R语言批量爬取网页时遭遇解析错误与数据重复问题求助
R语言批量爬取网页时遭遇解析错误与数据重复问题求助
嗨,我来帮你捋捋问题出在哪,你遇到的解析错误和数据重复,大概率和会话管理混乱、页面加载等待逻辑不完善以及错误处理不到位有关,咱们一步步来解决:
问题根源拆解
- 重复创建Chromote会话:你每次调用
test(i)都新建一个ChromoteSession,这不仅浪费系统资源,还可能导致之前的会话没被正确销毁,残留的状态会干扰后续请求,进而返回重复或错误的数据。 - 页面等待逻辑太弱:
loadEventFired只等页面触发加载完成事件,但有些动态渲染的内容可能在这个事件之后才生成,这时候获取的HTML大概率不完整,解析JSON自然会出错,甚至返回之前的缓存内容。 - tryCatch处理不完整:你的tryCatch没有定义错误处理分支,出错时可能默认返回最后一次成功的结果,或者把无效/重复值塞进列表,同时也没记录哪些
i值出了问题,不利于后续补爬。
优化方案与改进代码
1. 复用Chromote会话
把会话创建移到循环外面,整个爬取过程只用一个会话,用完及时关闭,避免资源泄漏和状态残留。
2. 完善页面等待逻辑
用navigate的wait_ = TRUE确保页面加载完成,再加上短暂的休眠时间,避免请求过快触发网站反爬,也给动态内容留足渲染时间。
3. 增强错误处理
在tryCatch里明确错误分支,记录出错的i值,出错时不把无效数据加入列表,方便后续补爬。
4. 优化列表构建
预先初始化列表长度,用索引赋值的方式添加元素,比c(ma_liste, list(...))更高效,也能避免潜在的重复元素问题。
改进后的完整代码:
library(rvest) library(chromote) library(jsonlite) library(dplyr) # 改进test函数:接收已创建的会话作为参数,避免重复创建 test <- function(session, i) { # 导航到目标页面,等待页面完全加载 session$Page$navigate(paste0("https://www.ecologie.gouv.fr/sru_api/api/towns/", i), wait_ = TRUE) # 短暂休眠,给动态内容留足渲染时间(可根据网站情况调整时长) Sys.sleep(0.8) # 获取页面完整HTML html <- session$Runtime$evaluate('document.documentElement.outerHTML') content <- read_html(html$result$value) data_json <- html_text(content) df <- fromJSON(data_json) return(df) } # 初始化单个Chromote会话 b <- ChromoteSession$new() # 预先初始化列表,指定长度提升效率 n <- 100 ma_liste <- vector("list", length = n - 1) # i从2到n,共n-1个元素 error_indices <- c() # 记录出错的页面索引 for (i in 2:n) { tryCatch({ # 用索引赋值,避免动态拼接列表的问题 ma_liste[[i - 1]] <- test(b, i) cat("成功爬取第", i, "页\n") }, error = function(e) { cat("爬取第", i, "页出错:", e$message, "\n") error_indices <- c(error_indices, i) }) } # 关闭会话,释放资源 b$close() # 过滤列表中的空值(出错的位置) ma_liste <- ma_liste[!sapply(ma_liste, is.null)] # 合并为数据框 dataframe <- do.call(rbind, ma_liste) dataframe <- as.data.frame(dataframe) # 查看出错的索引,方便后续补爬 print("出错的页面索引:") print(error_indices)
额外小建议
其实你爬的目标看起来是个JSON API接口,完全可以不用chromote模拟浏览器,直接用httr包请求接口,这样更稳定高效,也不会有页面渲染的问题:
library(httr) library(jsonlite) test_api <- function(i) { url <- paste0("https://www.ecologie.gouv.fr/sru_api/api/towns/", i) response <- GET(url) stop_for_status(response) # 请求出错时直接抛出错误 df <- fromJSON(content(response, "text")) return(df) } # 后续的循环、错误处理逻辑和上面一致即可
备注:内容来源于stack exchange,提问作者Alexique
相关产品推荐
相关产品推荐

