使用parLapply并行调用rvest爬取O*NET遇连接错误求助
解决方案
1. 降低并行规模+添加请求延迟
31核同时发起请求远超O*NET公共服务的承受能力,直接触发服务器拒绝连接或反爬限制。建议将并行核数降至8-12(预留2核给系统),同时给每个请求添加随机延迟,模拟人工访问节奏:
library(parallel) library(rvest) library(httr) # 带延迟、重试的爬取函数 scrape_soc <- function(title) { # 1-3秒随机延迟 Sys.sleep(runif(1, 1, 3)) result <- tryCatch({ url <- paste0("https://www.onetonline.org/find/quick?s=", URLencode(title)) # 模拟浏览器UA,避免被识别为爬虫 resp <- GET(url, user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36")) # 非200状态码时重试1次 if (status_code(resp) != 200) { Sys.sleep(5) resp <- GET(url, user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36")) if (status_code(resp) != 200) return(NA) } page <- read_html(resp) soc_code <- page %>% html_element("td:nth-child(1)") %>% html_text() soc_code }, error = function(e) { message(sprintf("Failed to process '%s': %s", title, e$message)) NA }) result } # 初始化并行集群(用8核) num_cores <- min(detectCores() - 2, 8) cl <- makeCluster(num_cores) clusterExport(cl, c("scrape_soc", "URLencode", "GET", "status_code", "read_html", "html_element", "html_text", "runif", "Sys.sleep")) clusterEvalQ(cl, { library(rvest) library(httr) }) # 分批处理150万条数据(每批1万条) batch_size <- 10000 total_batches <- ceiling(length(job_titles) / batch_size) all_results <- character(length(job_titles)) for (batch in 1:total_batches) { start <- (batch - 1) * batch_size + 1 end <- min(batch * batch_size, length(job_titles)) batch_titles <- job_titles[start:end] batch_res <- parLapply(cl, batch_titles, scrape_soc) all_results[start:end] <- unlist(batch_res) # 每批完成后保存进度,避免丢失 saveRDS(all_results, sprintf("soc_progress_batch_%d.rds", batch)) # 批次间额外延迟10秒,减轻服务器压力 Sys.sleep(10) } stopCluster(cl)
2. 修正tryCatch的作用范围
之前的tryCatch可能只包裹了部分逻辑,导致连接错误未被捕获。必须将GET请求、页面解析等所有可能出错的步骤全部纳入tryCatch范围,确保任何异常都能被捕获并返回NA,避免并行进程崩溃。
3. 会话保持优化
使用httr::handle建立持久会话,减少重复TCP连接的开销,提升请求稳定性:
# 在集群初始化前创建会话句柄 session_handle <- handle("https://www.onetonline.org") # 修改scrape_soc中的请求部分 resp <- GET(url, user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"), handle = session_handle)
4. 优先使用官方批量服务
O*NET提供官方开发者API和批量数据下载服务,相比网页爬取,官方渠道更稳定、合规,完全适配大规模数据查询需求,这是解决问题的最优方案。
内容的提问来源于stack exchange,提问作者abgeorge
相关产品推荐
相关产品推荐

