R语言网页爬取:批量填充统一字段与缺失值设为NA的实现
BJJ赛事数据爬取与DataFrame构建问题
我需要从指定页面爬取选手的组别、性别、腰带等级、体重等信息并整合成DataFrame,目前遇到两个技术问题:
- 组别、性别、腰带等级、体重仅在页面顶部出现一次,如何让这些信息自动填充到每位选手对应的DataFrame行中?
- 如何为缺失的日期、选手编号等信息填充NA值?当前因各爬取字段长度不一致,无法生成有效DataFrame。
现有代码如下:
library(rvest) library(tidyverse) MensUrl <- read_html('https://www.bjjcompsystem.com/tournaments/1869/categories/2053147') ## SCRAPE FIGHT INFO ------------------------------------------- ageDivision <- MensUrl %>% html_nodes('.category-title__age-division') %>% html_text() gender <- MensUrl %>% html_nodes('.category-title__age-division+ .category-title__label') %>% html_text() belt <- MensUrl %>% html_nodes('.category-title__label:nth-child(3)') %>% html_text() weight <- MensUrl %>% html_nodes('.category-title__label:nth-child(4)') %>% html_text() fightAndMat <- MensUrl %>% html_nodes('.bracket-match-header__where , .bracket-match-header__fight') %>% html_text() date = MensUrl %>% html_nodes('.bracket-match-header__when') %>% html_text() CompetitorNo = MensUrl %>% html_nodes('.match-card__competitor-n') %>% html_text() name = MensUrl %>% html_nodes('.match-card__competitor-description div:nth-child(1)') %>% html_text() gym = MensUrl %>% html_nodes('.match-card__club-name') %>% html_text() # create match df matches = data.frame('division' = ageDivision, 'gender' = gender, 'belt' = belt, 'weight' = weight, 'fightAndMat' = fightAndMat, 'date' = date, 'competitor' = CompetitorNo, 'name' = name, 'gym' = gym)
期望生成的DataFrame需包含每位选手对应的组别、性别等全局信息,缺失字段填充NA。
解决方案
1. 全局信息批量填充
页面顶部的组别、性别等是全局属性,只需将这些单值向量重复至与选手数量一致即可。以选手姓名的长度作为重复次数(每位选手必有姓名,长度最可靠),用rep()或rep_len()实现批量填充。
2. 字段长度对齐与NA填充
部分字段(如日期、选手编号)可能缺失,需确保所有向量长度一致,缺失位置自动补NA。用purrr::map_dfc()结合rep_len()可批量处理所有字段,统一长度并补全NA。
修改后的完整代码:
library(rvest) library(tidyverse) MensUrl <- read_html('https://www.bjjcompsystem.com/tournaments/1869/categories/2053147') ## 爬取全局信息(页面顶部) ageDivision <- MensUrl %>% html_nodes('.category-title__age-division') %>% html_text() gender <- MensUrl %>% html_nodes('.category-title__age-division+ .category-title__label') %>% html_text() belt <- MensUrl %>% html_nodes('.category-title__label:nth-child(3)') %>% html_text() weight <- MensUrl %>% html_nodes('.category-title__label:nth-child(4)') %>% html_text() ## 爬取选手及赛事细节 fightAndMat <- MensUrl %>% html_nodes('.bracket-match-header__where , .bracket-match-header__fight') %>% html_text() date <- MensUrl %>% html_nodes('.bracket-match-header__when') %>% html_text() CompetitorNo <- MensUrl %>% html_nodes('.match-card__competitor-n') %>% html_text() name <- MensUrl %>% html_nodes('.match-card__competitor-description div:nth-child(1)') %>% html_text() gym <- MensUrl %>% html_nodes('.match-card__club-name') %>% html_text() # 获取选手数量(以name的长度为准) total_competitors <- length(name) # 统一所有字段长度,自动填充NA matches_df <- map_dfc( list( division = ageDivision, gender = gender, belt = belt, weight = weight, fight_and_mat = fightAndMat, date = date, competitor_no = CompetitorNo, name = name, gym = gym ), ~rep_len(.x, length.out = total_competitors) ) %>% as.data.frame() # 可选:转为data.frame格式,如需tibble可去掉这行
代码说明
rep_len(.x, length.out = total_competitors):将每个向量调整为指定长度,不足部分自动补NA,解决字段长度不一致问题。- 全局信息(division、gender等)原本是单值,
rep_len会自动重复至选手数量,实现每行填充。 map_dfc批量处理所有字段,避免逐个手动调整,代码更简洁易维护。
内容的提问来源于stack exchange,提问作者bandcar
相关产品推荐
相关产品推荐

