使用rvest多页爬取时规避404错误的技术方案问询
解决方法
你遇到的问题是因为tryCatch返回了字符串"error 404",但后续代码仍尝试对这个字符串执行XML相关操作,自然会触发类型不匹配的错误。要跳过无效页面,只需要让无效URL对应的函数返回NULL,bind_rows会自动忽略这些空值。
方案1:用tryCatch包裹整个页面处理逻辑
修改getPageTable函数,把所有操作都放在tryCatch块内,遇到错误时直接返回NULL:
getPageTable <- function(url) { tryCatch({ # 原有的页面读取和处理逻辑 page <- read_html(url) gamedate <- page %>% html_element("div.scorebox_meta div") %>% html_text2() gameInfo <- page %>% html_elements("div.box h1") %>% html_text() headings <- page %>% html_elements("div.section_wrapper") %>% html_element("h2") %>% html_text() quarters <- grep("Q[1|2|3|4]", headings) tables <- page %>% html_elements("div.section_wrapper") %>% html_element("table") headings <- headings[quarters] tables <- tables[quarters] %>% html_table(header=FALSE) tables <- lapply(1:length(tables), function(i) { names(tables[[i]]) <- tables[[i]][2,] tables[[i]] <- tables[[i]][-c(1:2),] tables[[i]]$gamedate <- gamedate tables[[i]]$team <- headings[i] tables[[i]]$title <- gameInfo tables[[i]] }) df <- bind_rows(tables) df <- df %>% filter("Starters" != "Reserves" | "Starters" != "Team Totals" ) df }, error = function(e) { # 可选:输出错误提示,方便排查 message(paste("无法处理URL:", url, "错误信息:", e$message)) NULL }) }
当URL无效时,函数返回NULL,后续lapply生成的列表里的空值会被bind_rows自动跳过,最终只保留有效页面的数据。
方案2:先检查HTTP状态码(更高效)
如果不想等到加载页面时才发现错误,可以先发送HEAD请求检查URL的有效性,避免无效的页面加载:
首先加载httr包:
library(httr)
然后修改getPageTable函数:
getPageTable <- function(url) { # 先检查HTTP状态码,仅处理状态码为200的有效页面 resp <- HEAD(url) if (status_code(resp) != 200) { message(paste("URL不存在或无法访问:", url)) return(NULL) } # 后续原有的页面处理逻辑 page <- read_html(url) gamedate <- page %>% html_element("div.scorebox_meta div") %>% html_text2() gameInfo <- page %>% html_elements("div.box h1") %>% html_text() headings <- page %>% html_elements("div.section_wrapper") %>% html_element("h2") %>% html_text() quarters <- grep("Q[1|2|3|4]", headings) tables <- page %>% html_elements("div.section_wrapper") %>% html_element("table") headings <- headings[quarters] tables <- tables[quarters] %>% html_table(header=FALSE) tables <- lapply(1:length(tables), function(i) { names(tables[[i]]) <- tables[[i]][2,] tables[[i]] <- tables[[i]][-c(1:2),] tables[[i]]$gamedate <- gamedate tables[[i]]$team <- headings[i] tables[[i]]$title <- gameInfo tables[[i]] }) df <- bind_rows(tables) df <- df %>% filter("Starters" != "Reserves" | "Starters" != "Team Totals" ) df }
这种方法提前过滤无效URL,减少不必要的网络请求,效率更高。
最终效果
使用任意一种方案后,运行你的测试代码:
month <- c('02') year <- c('2024') day <- c('210','220','270','280') team <- c('CHI') dates <- expand.grid(team = team, year = year, month = month, day = day) urls <- dates |> mutate( url = make_url(team, year, month, day), team = team, date = paste(year, month, gsub('.{1}$', '', day), sep = '-'), .keep = 'unused' ) dfs <- lapply(urls$url, getPageTable) finalResult <- bind_rows(dfs) finalResult <- finalResult %>% separate("team", into=c("team", "quarter"), " \\(") finalResult$quarter <- sub("\\)", "", finalResult$quarter)
代码会自动跳过202402210CHI.html这个无效页面,只返回另外三个有效页面的数据。
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

