rvest: цикл / карта для извлечения нескольких таблиц с использованием html_node & html_table - PullRequest
2 голосов
/ 06 января 2020

Я пытаюсь программно получить все оценки за определенный день из Ссылка на NBA (я использовал 4 января 2020 года, в котором есть несколько игр). Я начал с создания списка целых чисел, чтобы обозначить количество набираемых очков:

games<- c(1:3)

Затем я использовал developer tools из своего браузера, чтобы определить, что содержит каждая таблица (вы можете использовать selector gadget) :

#content > div.game_summaries > div:nth-child(1) > table.team

Затем я использовал purrr::map для создания списка таблиц для извлечения, используя games:

map_list<- map(.x= '', paste, '#content > div.game_summaries > div:nth-child(', games, ') > table.teams', 
           sep = "") 
# check map_list
map_list

Затем я попытался запустить этот список через for l oop для генерации трех таблиц, используя tidyverse и rvest, что привело к ошибке:

for (i in map_list){
read_html('https://www.basketball-reference.com/boxscores/') %>% 
  html_node(map_list[[1]][i]) %>% 
  html_table() %>% 
  glimpse()
}

Error in selectr::css_to_xpath(css, prefix = ".//") : 
  Zero length character vector found for the following argument: selector
In addition: Warning message:
In selectr::css_to_xpath(css, prefix = ".//") :
  NA values were found in the 'selector' argument, they have been removed

Для справки, если я явно обозначу html или назову точное элемент из map_list, код работает как задумано (запустите ниже пункты для справки):

read_html('https://www.basketball-reference.com/boxscores/') %>% 
  html_node('#content > div.game_summaries > div:nth-child(1) > table.teams') %>% 
  html_table() %>% 
  glimpse()

read_html('https://www.basketball-reference.com/boxscores/') %>% 
  html_node(map_list[[1]][1]) %>% 
  html_table() %>% 
  glimpse()

Как мне сделать это со списком? Я смотрел на другие темы , но, несмотря на то, что они используют один и тот же сайт, они не являются той же проблемой.

Ответы [ 2 ]

2 голосов
/ 06 января 2020

Используя ваш текущий map_list, если вы хотите использовать for l oop, это то, что вы должны использовать

library(rvest)

for (i in seq_along(map_list[[1]])){
  read_html('https://www.basketball-reference.com/boxscores/') %>% 
   html_node(map_list[[1]][i]) %>% 
   html_table() %>% 
   glimpse()
}

, но я думаю, что это проще, так как вам не нужно используйте map для создания map_list, поскольку paste векторизовано:

map_list<- paste0('#content > div.game_summaries > div:nth-child(', games, ') > table.teams')
url <- 'https://www.basketball-reference.com/boxscores/'
webpage <- url %>% read_html()

purrr::map(map_list, ~webpage %>% html_node(.x) %>% html_table)

#[[1]]
#       X1  X2    X3
#1 Indiana 111 Final
#2 Atlanta 116      

#[[2]]
#        X1  X2    X3
#1  Toronto 121 Final
#2 Brooklyn 102      

#[[3]]
#       X1  X2    X3
#1  Boston 111 Final
#2 Chicago 104      
1 голос
/ 06 января 2020

Эта страница достаточно прямолинейна. Вот возможное решение: сначала удалите узлы сводки игры "div with class = game_summary". Это обеспечивает список всех сыгранных игр. Также это позволяет использовать функцию html_node, которая гарантирует возврат, сохраняя при этом размеры списка равными.

Каждая сводка игры состоит из трех подтаблиц, первая и третья таблицы могут быть обработаны напрямую. Вторая таблица не имеет назначенного класса, что делает ее более сложной для извлечения.

library(rvest)

page <- read_html('https://www.basketball-reference.com/boxscores/')

#find all of the game summaries on the page
games<-page %>% html_nodes("div.game_summary")

#Each game summary has 3 sub tables
#game score is table 1 of class=teams
#the stats is table 3 of class=stats
# the quarterly score is the second table and does not have a class defined
  table1<-games %>%  html_node("table.teams") %>% html_table()
  stats <-games %>%  html_node("table.stats") %>% html_table()
  quarter<-sapply(games, function(g){
                      g %>%  html_nodes("table") %>% .[2] %>% html_table()
                  })
...