使用 Rvest、Lapply、Rbind 和 Selector Gadget 进行网页抓取

Web Scraping with Rvest, Lapply, Rbind, and Selector Gadget

我是网络抓取的新手,在抓取网站中的多个页面时遇到困难。感谢社区的任何反馈!

目标:从 2019 年开始抓取每个团队的统计数据cfbstats.com,并将每个团队的数据放入一个数据框或自定义团队数据框中。

操作: 在下面的代码中,我编写了一个 html 调用,将每个团队的(小示例)唯一标识符粘贴到 html 代码中。之后,我使用 lapply 函数和 rvest 来提取每个团队的数据。最后,rbind 和 do.call 用于连接所有的拉动。

问题: 在 @Dave2e 的帮助下,我意识到 rbind 结合了所有被抓取的数据表时遇到了问题。从网络抓取中加入数据表有什么建议吗? match.names(clabs, names(xi)) 中的错误: 名称与以前的名称不匹配

library(tidyverse)
library(rvest)

team_id <- c(721, 5, 8)
teams <- paste('http://cfbstats.com/2019/team/', team_id, '/index.html', sep = "")

df_team_stats <- lapply(teams, function(i){
  webpage <- read_html(i)
  team_table <- html_nodes(webpage, '.team-statistics')
  overall_stats <- html_table(team_table)[[1]]
})

finaldf <- do.call(rbind, df_team_stats) 

这里有几个问题。首先,您的 lapply 不是 return 数据框列表,而是列表列表(只是每个子列表都有一个数据框作为其唯一内容)。

其次,当您将数据框绑定在一起时,它们需要具有相同的列名。在您的例子中,团队的名称充当列名称。如果只是覆盖这个,你将不知道一行是指哪个团队的数据,所以你需要添加一个“团队”列并将其他列的名称标准化:

library(dplyr)
library(rvest)

team_id <- c(721, 5, 8)
teams   <- paste('http://cfbstats.com/2019/team/', team_id, '/index.html', sep = "")

df_team_stats <- lapply(teams, function(i){
  webpage   <- read_html(i)
  all_stats <- html_nodes(webpage, xpath = "//table[@class='team-statistics']") %>%
               html_table() %>% `[[`(1)
  all_stats$team <- rep(names(all_stats)[2], nrow(all_stats))
  names(all_stats)[1:2] <- c("stat", "home")
  all_stats[,c(4, 1:3)]
})

as_tibble(bind_rows(df_team_stats))
#> # A tibble: 99 x 4
#>    team     stat                                   home          Opponents      
#>    <chr>    <chr>                                  <chr>         <chr>          
#>  1 Air For~ Scoring:  Points/Game                  34.1          19.8           
#>  2 Air For~ Scoring:  Games - Points               13 - 443      13 - 258       
#>  3 Air For~ First Downs:  Total                    286           216            
#>  4 Air For~ First Downs:  Rushing - Passing - By ~ 227 - 52 - 7  77 - 131 - 8   
#>  5 Air For~ Rushing:  Yards / Attempt              5.14          3.49           
#>  6 Air For~ Rushing:  Attempts - Yards - TD        755 - 3881 -~ 375 - 1307 - 11
#>  7 Air For~ Passing:  Rating                       187.92        141.25         
#>  8 Air For~ Passing:  Yards                        1602          2848           
#>  9 Air For~ Passing:  Attempts - Completions - In~ 126 - 68 - 6~ 377 - 238 - 7 ~
#> 10 Air For~ Total Offense:  Yards / Play           6.22          5.53           
#> # ... with 89 more rows

reprex package (v0.3.0)

于 2020-06-27 创建

也许 dplyr 的 bind_cols() 在这里很有用。所以像:

library(tidyverse)
library(janitor)
library(rvest)

team_id <- c(721, 5, 8)
teams <- paste('http://cfbstats.com/2019/team/', team_id, '/index.html', sep = "")


df_team_stats <- lapply(teams, function(i){
  webpage <- read_html(i)
  team_table <- html_nodes(webpage, 'table.team-statistics')
  overall_stats <- html_table(team_table)[[1]] %>% 
    clean_names() %>% 
    column_to_rownames(var = "x")
})

finaldf <- df_team_stats %>% 
  bind_cols() %>% 
  rownames_to_column(var = "Statistics")