#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