【问题标题】:Combine two separate webpage scrapes using the same url into one scrape using rvest and map function使用 rvest 和 map 功能将使用相同 url 的两个单独的网页抓取合并为一个抓取
【发布时间】:2023-03-26 18:08:01
【问题描述】:

我已经成功地编写了两个可以正常工作的独立抓取功能,但我想通过使用 purrr 中的地图功能将它们组合成一个单独的抓取来继续我的学习。这两个刮痕甚至来自我称之为“url_final”的活动页面的索引。以下是该索引中的两个活动页面示例:

https://www.sports-reference.com/cbb/players/ken-tabaka-1.html
https://www.sports-reference.com/cbb/players/bobby-adair-1.html

我正在抓取球员的姓名、身高和他们参加的赛季(从表格中提取的赛季数据并占据第一列的所有数据)您会注意到在第二个链接中没有表格。这是一个罕见的情况,但我把它作为一个例子,因为这需要我使用另一个了不起的 SO 大师提供给我的 try catch 函数。

这是第一个使用大索引“url_final”作为 .x 的单独抓取函数:

library(rvest)
library(curl)
library(tidyverse)

name_age <- map_dfr(.x = url_final,
                .f = function(x){Sys.sleep(.3); cat(1); 

 player <- read_html(curl(x, handle = curl::new_handle("useragent" = "Mozilla/5.0"))) %>% 
  html_nodes("#meta :nth-child(1)") %>%
  html_text() %>%
  .[[1]] %>%
   as.data.frame()
                    })

这是第二次抓取,使用相同的 url 索引并从页面上的第一个表中获取季节,注意,您可以从上面的第一个 url 示例中看到它包含该表,但不包含第二个 URL。

player_seasons <- map_dfr(.x = url_final,
          .f = function(x){Sys.sleep(.3); cat(1); 
             tryCatch({
             fyr <- read_html(curl::curl(x, 
                  handle = curl::new_handle("useragent" = "Mozilla/5.0"))) %>%
                  html_table() %>% .[[1]] 

           fyr <- fyr %>%
                   select(1) %>%
                   mutate(name = str_extract(string = x, 
                     pattern = "(?<=cbb/players/).*?(?=-\\d\\.html)"))
           }, error = function(e) message('Skipping url', x))
        })

我尝试将这两者组合成一个地图功能,但无济于事。我猜解决方案很简单。我想找到一种方法将所有数据映射为单个 df。

重要提示

在大多数情况下,每个球员都会被淘汰多个赛季,我想这可能是我在解决这个问题时遇到问题的原因。理想情况下,我只需要表格显示的最近一年。例如,我提供的第一个 URL 示例(Ken Tabaka 个人资料页面)我真的只对保留“1970/71”1969-70 感兴趣,并且无论如何稍后都会被过滤掉。

谢谢大家!

【问题讨论】:

  • 嗨 Jeff,你想以什么方式组合这两个函数的输出?
  • @Bas 理想情况下是数据框或小标题。如果有必要,一份清单至少也是可以接受的。
  • @Ronak 在下面提供了答案。一个小提示:你使用html_nodes,然后用.[[1]] 选择第一个元素,这可以通过使用html_node(单数)来缓解,它会自动选择第一个。
  • 嗨,杰夫,下面的答案对我有用,在 R 4.0.0 上没有任何错误。和dplyr 1.0.0。我不确定您是否需要为此更新任何软件包。如果它仍然不起作用,请尝试几件事 1) 使用 map 而不是 map_dfr。 2)使用list(first, second)而不是tibble(first, second) 3)同时执行1和2。
  • @RonakShah 使用 Map 而不是 map_dfr 有效!我有 95k 的 url 最终将映射到一个列表中,但不确定这是可取的,但我认为 R 应该能够处理它。我不完全确定之后如何将列表的所有元素组合到一个数据框中,但我敢打赌我可以研究一下。一如既往地感谢你。你是最棒的罗纳克!

标签: r web-scraping rvest


【解决方案1】:

你可以试试:

library(rvest)
library(curl)
library(tidyverse)

url_final <- c('https://www.sports-reference.com/cbb/players/ken-tabaka-1.html',
               'https://www.sports-reference.com/cbb/players/bobby-adair-1.html')


temp <- map_dfr(.x = url_final,
    .f = function(x){Sys.sleep(.3); cat(1);       
    webpage <- read_html(curl(x, handle = new_handle("useragent"="Mozilla/5.0"))) 

      first <- webpage %>% html_nodes("#meta :nth-child(1)") %>%
        html_text() %>% .[[1]] %>% tibble(text = .)
      second <- tryCatch({webpage %>% 
                  html_table() %>% .[[1]] %>%
                  select(1) %>%
                   mutate(name = str_extract(string = x, 
                          pattern = "(?<=cbb/players/).*?(?=-\\d\\.html)"))
      }, error = function(e) 
            {message('Skipping url', x);return(tibble(Season = NA, name = NA))})
      tibble(first, second)
    })

由于我们不能拥有长度不等的数据帧,因此如果发生异常,请添加一个带有 NA 的空 tibble。此外,您可能会考虑在最终输出中添加 URL 或某个唯一键作为列,以识别哪一行来自何处​​。

【讨论】:

    猜你喜欢
    • 2020-07-18
    • 2019-02-17
    • 2020-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-11
    相关资源
    最近更新 更多