извлечение таблицы с веб-страницы с помощью R

#r #web-scraping

#r #очистка веб-страницы

Вопрос:

Я пытаюсь извлечь всю таблицу с этой страницы, используя R, для html_node я передал «table». В консоли вывод странный. Данные доступны на веб-странице, но в консоли 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
  

Комментарии:

1. Вместо изображения кода добавьте свой код в вопрос

Ответ №1:

Это приведет к объединению всех таблиц в единый фрейм данных:

 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))
  

Надеюсь, это поможет.

Комментарии:

1. Как я могу установить конкретный год для каждой строки? как указано выше для 2009 года, мне нужно добавить год для «таблиц», например, для первых 10 строк значение year равно 2017, а для следующих 10 лет значение 2008, подобное этому для 90 строк

2. Спасибо. Также узнал о функции mutate.

Ответ №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 годы. Таким образом, мы могли бы добавить эти годы в качестве имен в список, а затем связать таблицы вместе со столбцом для year:

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

Комментарии:

1. При попытке привязать year к таблицам я получаю приведенную ниже ошибку. Ошибка в именах наборов (tables, c(2017, 2008:2011, 2013:2016)) : ‘ атрибут names [9] должен иметь ту же длину, что и вектор [8]

2. Это говорит о том, что имен (9) больше, чем таблиц. Список должен иметь длину 9, используя приведенный код и ваш пример URL.

Ответ №3:

В списке, который вы назвали, есть несколько элементов table . (Не очень хорошая практика: есть функция с таким именем.)

 str(tbl)
List of 18
 $ :'data.frame':   12 obs. of  45 variables:
  ..$ X1 : chr [1:12] "RanknGroup/companynDirect premiums written (1)nMarket share (2)n1nState Farm Mutual Automobile Insurancen"| __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