【问题标题】:extract table from webpage using R使用R从网页中提取表格
【发布时间】:2021-11-29 15:20:31
【问题描述】:

我正在尝试使用 R 从this page 中提取所有表格,因为 html_node 我已经通过了“表格”。在控制台中,输出很奇怪。数据在网页中可用,但在 R 控制台中显示 NA。请建议我在哪里犯了错误。

library(xml2)
library(rvest)
url <- "https://www.iii.org/table-archive/21110" 
page <- read_html(url) #Creates an html document from URL
table <- html_table(page, fill = TRUE) #Parses tables into data frames
table

部分输出: X4 X5 X6

  1  Direct premiums written (1) Market share (2)  1
    2             Market share (2)             <NA> NA
    3                        10.6%             <NA> NA
    4                          6.0             <NA> NA
    5                          5.4             <NA> NA
    6                          5.4             <NA> NA
    7                          5.2             <NA> NA
    8                          4.5             <NA> NA
    9                          3.3             <NA> NA
    10                         3.2             <NA> NA
    11                         3.0             <NA> NA
    12                         2.2             <NA> NA
                                           X7          X8    X9 X10
    1  State Farm Mutual Automobile Insurance $51,063,111 10.6%   2
    2                                    <NA>        <NA>  <NA>  NA
    3                                    <NA>        <NA>  <NA>  NA
    4                                    <NA>        <NA>  <NA>  NA
    5                                    <NA>        <NA>  <NA>  NA
    6                                    <NA>        <NA>  <NA>  NA
    7                                    <NA>        <NA>  <NA>  NA
    8                                    <NA>        <NA>  <NA>  NA
    9                                    <NA>        <NA>  <NA>  NA
    10                                   <NA>        <NA>  <NA>  NA
    11                                   <NA>        <NA>  <NA>  NA
    12                                   <NA>        <NA>  <NA>  NA

【问题讨论】:

  • 在问题中添加代码而不是代码图像

标签: r web-scraping


【解决方案1】:

列表中有多个您已命名为 table 的项目。 (不是一个好的做法:有一个同名的函数。)

str(tbl)
List of 18
 $ :'data.frame':   12 obs. of  45 variables:
  ..$ X1 : chr [1:12] "Rank\nGroup/company\nDirect premiums written (1)\nMarket share (2)\n1\nState Farm Mutual Automobile Insurance\n"| __truncated__ "Rank" "1" "2" ...
  ..$ X2 : chr [1:12] "Rank" "Group/company" "State Farm Mutual Automobile Insurance" "Berkshire Hathaway Inc." ...
  ..$ X3 : chr [1:12] "Group/company" "Direct premiums written (1)" "$64,892,583" "38,408,251" ...
snippped rest of long output

也许你只想要最后一个?

tbl[[18]]
   Rank                            Group/company
1     1   State Farm Mutual Automobile Insurance
2     2                  Berkshire Hathaway Inc.
3     3                           Liberty Mutual
4     4                           Allstate Corp.
5     5                        Progressive Corp.
6     6                 Travelers Companies Inc.
7     7                               Chubb Ltd.
8     8                  Nationwide Mutual Group
9     9 Farmers Insurance Group of Companies (3)
10   10                     USAA Insurance Group
   Direct premiums written (1) Market share (2)
1                  $62,189,311            10.2%
2                   33,300,439              5.4
3                   32,217,215              5.3
4                   30,875,771              5.0
5                   23,951,690              3.9
6                   23,918,048              3.9
7                   20,786,847              3.4
8                   19,756,093              3.2
9                   19,677,601              3.2
10                  18,273,675              3.0

不;回到页面,很明显你想要第一个,但它的结构似乎被误解了,数据被排列为“宽”,所有数据都位于第一行。所以一些列正在显示,而其余的数据似乎被弄乱了;只取第 2:4 列:

tbl[[1]][ ,c('X2','X3','X4')]
                                         X2                          X3
1                                      Rank               Group/company
2                             Group/company Direct premiums written (1)
3    State Farm Mutual Automobile Insurance                 $64,892,583
4                   Berkshire Hathaway Inc.                  38,408,251
5                            Liberty Mutual                  33,831,726
6                            Allstate Corp.                  31,501,664
7                         Progressive Corp.                  27,862,882
8                  Travelers Companies Inc.                  24,875,076
9                                Chubb Ltd.                  21,266,737
10                     USAA Insurance Group                  20,151,368
11 Farmers Insurance Group of Companies (3)                  19,855,517
12                  Nationwide Mutual Group                  19,218,907
                            X4
1  Direct premiums written (1)
2             Market share (2)
3                        10.1%
4                          6.0
5                          5.3
6                          4.9
7                          4.3
8                          3.9
9                          3.3
10                         3.1
11                         3.1
12                         3.0

【讨论】:

    【解决方案2】:

    这些表格存在一些问题。

    首先,我认为如果你指定表的类,你会得到更好的结果。在这种情况下,.tablesorter

    其次,您会注意到,在某些表格中,第二列标题为Group,在其他情况下为Group/company。这就是导致NA 的原因。因此,您需要重命名列以使所有表保持一致。

    您可以像这样获得具有重命名列标题的表列表:

    tables <- page %>% 
      html_nodes("table.tablesorter") %>% 
      html_table() %>% 
      lapply(., function(x) setNames(x, c("rank", "group_company", 
                                          "direct_premiums_written", "market_share")))
    

    查看网页,我们看到这些表是 2017 年、2008 年到 2011 年和 2013 年到 2016 年的。所以我们可以将这些年份作为名称添加到列表中,然后将这些表与年份列绑定在一起:

    library(dplyr)
    tables <- setNames(tables, c(2017, 2008:2011, 2013:2016)) %>% 
      bind_rows(.id = "Year")
    

    【讨论】:

    • 我在尝试将年份绑定到表格时遇到错误。 setNames(tables, c(2017, 2008:2011, 2013:2016)) 中的错误:'names' 属性 [9] 必须与向量 [8] 的长度相同
    • 这告诉你名字(9)比表格多。该列表的长度应为 9,使用给定的代码和您的示例 URL。
    【解决方案3】:

    这会将所有表放入一个数据框中:

    library(tidyverse)
    library(rvest)
    
    
    url <-  "https://www.iii.org/table-archive/21110"
    
    df <- url %>% 
      read_html() %>% 
      html_nodes("table") %>% 
      html_table(fill = T) %>% 
      lapply(., function(x) setNames(x, c("Rank", "Company", "Direct_premiums_written", 
                                          "Market_share")))
    
    tables <- data.frame()
    
    for (i in seq(2,18,2)) {
        temp <- df[[i]] 
      tables <- bind_rows(tables, temp)
    }
    

    然后,您可以根据需要对其进行子集化。例如,让我们从代表 2009 年的第三个表中提取信息:

    table_2009 <- tables[21:30,] %>% 
              mutate(Year = 2009)
    

    一次添加所有年份:

    years <- c(2017, 2008, 2009, 2010, 2011, 2013, 2014, 2015, 2016)
    tables <- tables %>% 
              mutate(Year = rep(years, each = 10))
    

    希望这会有所帮助。

    【讨论】:

    • 如何为每一行设置特定年份?正如你上面提到的 2009 年,我需要为“表格”添加年份,比如前 10 行的年份值是 2017 年,下一个 10 年的值是 2008 年,就像 90 行一样
    • 谢谢。也了解了 mutate 函数。
    猜你喜欢
    • 1970-01-01
    • 2014-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多