【问题标题】:Add on a column to each table while webscraping with rvest在使用 rvest 进行网络抓取时向每个表添加一列
【发布时间】:2019-03-25 15:17:28
【问题描述】:

我正在尝试抓取此 webpage 的最后五个日期。这里我有seq_dates_test(我想在那个网页上抓取的日期序列):

structure(c(17975, 17976, 17977, 17978, 17979), class = "Date")

我正在使用以下代码块成功抓取这些日期

url <- "http://mcsafetyfeed.org/incidents.php?date="

url %>% 
  map2_chr(seq_dates_test,paste0) %>% 
  map_df(. %>% 
    read_html() %>% 
      html_nodes("table") %>% 
    html_table(header = TRUE) %>%
    # Extract out first element of list
    magrittr::extract2(1)
    )

但是,我想mutate 每个表的日期列(对应于每个日期)。我尝试在extract2 之后添加mutate(Date = seq_dates_test),但出现此错误...

mutate_impl(.data, dots) 中的错误:列 Date 的长度必须为 285(行数)或 1,而不是 5



更新:我将如何更改我的代码,以便如果表 X 的长度为 0,我会跳过该表并继续抓取下一个表?

【问题讨论】:

    标签: r rvest purrr


    【解决方案1】:

    paste 是矢量化的,所以我们不需要map2。我们可以直接paste带有日期的'url'并提取表格并使用.id通过命名为vector创建一个'Date'列

    library(tidyverse)
    out <- map_df(set_names(paste0(url, seq_dates_test), seq_dates_test), ~
          .x %>% 
             read_html() %>% 
             html_nodes("table") %>% 
             html_table(header = TRUE) %>%    
             magrittr::extract2(1), .id = 'Date')
    
    dim(out)
    #[1] 1365    6
    
    head(out)
    #        Date     Time                                                         Event                               Address     Responding Agency
    #1 2019-03-20 23:51:00                                             Parking complaint              1398 DEWEY AV, Rochester Rochester City Police
    #2 2019-03-20 23:12:00 Dangerous condition - no immediate danger to life or property        2970 W HENRIETTA RD, Henrietta  Monroe County Police
    #3 2019-03-20 22:50:00                                                 Odor of smoke          2349 E RIDGE RD, Irondequoit     Ridge Culver Fire
    #4 2019-03-20 22:44:00                                           Dangerous condition          DENISE RD/LAKE AV, Rochester Rochester City Police
    #5 2019-03-20 22:00:00                                             Parking complaint               3150 W RIDGE RD, Greece         Greece Police
    #6 2019-03-20 21:58:00           Accident of motor vehicles involving unknown injury SB RT 590 AT BROWNCROFT BL, Rochester New York State Police
    #       Event ID
    #1 CTYP190793429
    #2 MCOP190793334
    #3 RCUF190793284
    #4 CTYP190793264
    #5 GREP190793188
    #6 NYSP190793186
    

    更新

    如果我们需要进行错误检查并返回默认值,可以使用 purrr 中的 tryCatchpossibly

    f1 <- function(x) {
            x %>%
               read_html() %>% 
               html_nodes("table") %>% 
               html_table(header = TRUE) %>%    
               magrittr::extract2(1)
    
    
    }            
    pos1 <- possibly(f1, otherwise = NULL, quiet = TRUE)
    
    outlst1 <- map(set_names(paste0(url, seq_dates_test), 
                      seq_dates_test), pos1, .id = 'Date')
    

    然后过滤掉NULL元素

    bind_rows(discard(outlst1, is.null))
    

    数据

    seq_dates_test <- structure(c(17975, 17976, 17977, 17978, 17979), class = "Date")
    url <- "http://mcsafetyfeed.org/incidents.php?date="
    

    【讨论】:

    • 感谢您的回答。但是这mutate 每个表都有一个日期列吗?
    • 您介意看看我的附加问题吗?我将它添加到我的原始帖子中。谢谢!
    • @JasonBalk 我想你可能需要tryCatch,如果代码中有任何错误,你可以tryCatch({.x %&gt;% ..}, error = function(e) return NULL)然后使用discard(out, is.null)
    • 我刚刚赞成你的问题并接受它作为答案
    【解决方案2】:

    您的流程略有变化,因为我们希望为每个数据帧添加一个新的Date 列,我们可以在map 上添加seq_dates_test,而不是粘贴的网址。

    library(rvest)
    
    map(seq_dates_test, function(x) 
             paste0(url, x) %>%
                   read_html() %>% 
                   html_nodes("table") %>% 
                   html_table(header = TRUE) %>%
                   magrittr::extract2(1) %>%
                   mutate(Date = x))
    

    数据

    seq_dates_test <- structure(c(17975, 17976, 17977, 17978, 17979), class = "Date")
    url <- "http://mcsafetyfeed.org/incidents.php?date="
    

    【讨论】:

    • 你介意看看我的附加问题吗?我将它添加到我的原始帖子中。谢谢!
    猜你喜欢
    • 2020-08-28
    • 1970-01-01
    • 1970-01-01
    • 2019-10-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多