readHTMLTable и rvest не работают для очистки таблицы HTML

Я пытался очистить данные из таблицы HTML с проблемами.

url <- "http://www.njweather.org/data/daily"
Precip <- url %>%
    html() %>%
    html_nodes(xpath='//*[@id="dataout"]') %>%
    html_table()

это возвращает:

Warning message:
    'html' is deprecated. Use 'read_html' instead. See help("Deprecated")

и Precip List без каких-либо значений.

Я также попытался использовать функцию readHTMLTable():

readHTMLTable("http://www.njweather.org/data/daily", header = TRUE, stringAsFactors = FALSE)

это возвращает другой пустой список.


person nick    schedule 19.10.2016    source источник
comment
На сайте есть кнопка для загрузки CSV, что является простым вариантом здесь.   -  person alistaire    schedule 19.10.2016
comment
Я знаю, но из-за обстоятельств, связанных с ограничениями на моем компьютере, я надеялся избежать ежедневной загрузки CSV-файла. Я попробовал пакет RSelenium, но он требует прав администратора, которых у меня нет.   -  person nick    schedule 19.10.2016


Ответы (2)


К сожалению, это «Сохранить в CSV» — это элемент управления Shockwave/Flash, который просто извлекает содержимое JSON со страницы, поэтому нет возможности вызвать его напрямую (через URL-адрес), но его можно было бы щелкнуть в контексте веб-диска Firefox RSelenium (но …фу!).

Вместо того, чтобы использовать RSelenium или более новые пакеты веб-драйверов, могу ли я предложить некоторую хирургию содержимого узла gsub(), которая затем использует V8 для оценки содержимого:

library(dplyr)
library(rvest)
library(readr)
library(V8)

ctx <- v8()

pg <- read_html("http://www.njweather.org/data/daily")

html_nodes(pg, xpath=".//script[contains(., '#dtable')]") %>% 
  html_text() %>% 
  gsub("^.*var json", "var json", .) %>% 
  gsub("var dTable.*", "", .) %>% 
  JS() %>% 
  ctx$eval()

ctx$get("json")$aaData %>% 
  type_convert() %>% 
  glimpse()
## Observations: 66
## Variables: 16
## $ city                 <chr> "Berkeley Twp.", "High Point Monument", "Pequest", "Haworth", "Sicklerville", "Howell"...
## $ state                <chr> "NJ", "NJ", "NJ", "NJ", "NJ", "NJ", "NJ", "NJ", "NJ", "NJ", "NJ", "NJ", "NJ", "NJ", "N...
## $ date                 <date> 2016-10-19, 2016-10-19, 2016-10-19, 2016-10-19, 2016-10-19, 2016-10-19, 2016-10-19, 2...
## $ source               <chr> "Mesonet", "SafetyNet", "Mesonet", "Mesonet", "Mesonet", "Mesonet", "Mesonet", "Mesone...
## $ DT_RowId             <int> 1032, 1030, 1029, 1033, 1034, 3397, 1101, 471, 454, 314, 299, 315, 316, 450, 317, 3398...
## $ temperaturemax_daily <int> 84, 73, 84, 85, 86, 85, 87, 81, 83, 83, 83, 83, 80, 81, 84, 86, 84, 72, 85, 85, 85, 84...
## $ temperaturemin_daily <int> 65, 63, 56, 65, 63, 66, 66, 64, 63, 66, 62, 64, 66, 62, 62, 65, 66, 67, 62, 64, 65, 62...
## $ dewpointmax_daily    <int> 68, NA, 65, 67, 68, 68, 68, 65, NA, NA, NA, NA, NA, NA, 69, 68, 69, 68, 69, 70, 67, 67...
## $ dewpointmin_daily    <int> 63, NA, 56, 60, 62, 63, 61, 55, NA, NA, NA, NA, NA, NA, 62, 62, 61, 65, 61, 63, 62, 61...
## $ relhumidmax_daily    <int> 94, NA, 99, 94, 96, 91, 92, 90, NA, NA, NA, NA, NA, NA, 102, 93, 88, 94, 99, 94, 94, 9...
## $ relhumidmin_daily    <int> 50, NA, 39, 45, 48, 51, 43, 41, NA, NA, NA, NA, NA, NA, 51, 46, 49, 83, 51, 51, 48, 48...
## $ pressuremax_daily    <dbl> 29.97, NA, 29.97, 29.96, 30.02, 30.03, 29.99, 30.04, NA, NA, 30.01, 30.04, NA, 30.00, ...
## $ pressuremin_daily    <dbl> 29.86, NA, 29.86, 29.84, 29.91, 29.90, 29.88, 29.90, NA, NA, 29.91, 29.95, NA, 29.88, ...
## $ precip_daily         <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
## $ windspmax_daily      <int> 17, 32, 16, 12, 8, 13, 15, 21, 13, 12, 10, 14, 19, NA, 13, 10, 11, 15, 15, 10, 13, 13,...
## $ windspmaxdir_daily   <chr> "SW", NA, "WSW", "NW", "W", "WSW", "WSW", "W", "S", NA, NA, NA, NA, NA, "SSW", "SSW", ...

Также прочитайте об изменениях в rvest и xml2. Переключение на read_html() должно быть чем-то, что вы получите в мышечной памяти (html() в какой-то момент исчезнет).

person hrbrmstr    schedule 19.10.2016
comment
Большое спасибо, это было очень полезно! - person nick; 24.10.2016

Вот еще один вариант, который использует только пакеты rvest и stringr. В таком случае все данные хранятся на веб-странице, их просто нужно извлечь. Записи хранятся в пределах { } с именем первого поля «город». Этот шаг требует некоторого следа и ошибок, чтобы найти записи, чтобы определить структуру/порядок. Вызов функции str_locate_all выполняет этот поиск нежадным методом. После извлечения этих строк (записей) остается только проанализировать значения из каждого поля и создать окончательный фрейм данных.

library(rvest)
library(stringr)

#read web page
pg <- read_html("http://www.njweather.org/data/daily")

#find data of interest {"first field.*? }
#find data within brackets with the first field named city then any number of characters(.*) - not greedy(?)
#finds start and stop
recStartStop<-str_locate_all(pg, "\\{ \"city.*?\\}")[[1]]
#extract the records out from page
records<-str_sub(pg, recStartStop[,1]+1, recStartStop[,2]-1)

#replaces , within the string if necessary
#records<-gsub(", ", "_", records  )

#split and reshape the data in a data frame
records<-strsplit(gsub("\"", "", records), ',')
columnsNeeded<-length(records[[1]])
data<-sapply(strsplit(unlist(records), ":"), FUN=function(x){x[2]})
#if the number of fields is not consisten (columnsNeeded) this will error
df<-data.frame(matrix(data, ncol=columnsNeeded, byrow=TRUE))

#update column names
#name the column names
names(df)<-sapply(strsplit(unlist(records[1]), ":"), FUN=function(x){x[1]})

Надеюсь, комментарии в коде достаточно ясно объясняют каждый шаг.

person Dave2e    schedule 28.10.2016