使用map_dfr爬取网页:解决元素缺失导致循环中断及列报错
解决网页爬取中缺失嵌套表格的报错问题
错误原因分析
- 不必要的
map_dfr使用:对单个HTML文档使用map_dfr会遍历文档所有节点,导致生成的offense/defense数据框行数不符合预期。 - 类型不匹配:
possibly的otherwise返回字符串"na",但正常场景下该列是嵌套数据框,类型冲突导致赋值失败。 - 尺寸不匹配:缺失表格时返回空数据框(行数为0),无法与两行的linescore数据框匹配。
修正后的代码
library(tidyverse) library(rvest) library(RSelenium) library(netstat) library(janitor) library(glue) # 启动Selenium驱动 rs_driver_object <- rsDriver(browser = "firefox", verbose = F, chromever = NULL, port = free_port()) remDr <- rs_driver_object$client # 目标网页列表 games <- c( "https://www.pro-football-reference.com/boxscores/197301140mia.htm", "https://www.pro-football-reference.com/boxscores/196010230was.htm" ) # 定义表格提取与嵌套的辅助函数 extract_and_nest_table <- function(page, table_prefix) { page %>% html_element(xpath = glue("//*[@id='all_{table_prefix}']")) %>% # 精准定位单个表格 html_table(header = F) %>% # 禁用默认表头,后续手动设置 as.data.frame() %>% janitor::row_to_names(row_number = 1) %>% # 将第一行设为列名 janitor::clean_names() %>% # 清理列名格式 nest(data = everything()) %>% # 将所有列嵌套为list列 pull(data) # 提取list列,返回单个列表元素 } # 包装函数处理缺失表格的情况 safe_extract <- possibly(extract_and_nest_table, otherwise = list(tibble())) # 批量爬取并整合数据 test_df <- map_dfr(games, function(game_pull) { Sys.sleep(3) remDr$navigate(game_pull) x <- remDr$getPageSource() %>% unlist() page <- read_html(x) # 提取比赛得分表 linescore <- page %>% html_element(xpath = "//table[@class='linescore nohover stats_table no_freeze']") %>% html_table() %>% as.data.frame() %>% setNames(c("trash", "team", "q1", "q2", "q3", "q4", "final")) %>% select(-trash) # 移除无用列 # 安全提取攻防表格 offense_table <- safe_extract(page, "player_offense") defense_table <- safe_extract(page, "player_defense") # 添加嵌套表格列(自动循环匹配两行数据) linescore %>% mutate( offense = offense_table, defense = defense_table ) }) # 关闭驱动 remDr$close() rs_driver_object$server$stop()
关键改进点
- 使用
html_element(单数)精准定位单个表格,避免返回多个元素。 - 辅助函数返回包含嵌套数据框的列表,确保类型一致性。
possibly的otherwise返回空tibble的列表,保证与正常数据结构匹配,可自动循环填充到多行数据中。- 移除无用的
trash列,简化结果数据框。
内容的提问来源于stack exchange,提问作者Jeff Henderson
相关产品推荐
相关产品推荐

