Веб-просмотр таблиц, созданных с использованием JavaScript
Я пытаюсь очистить таблицу на вкладке "Коды" на этом сайте (большая таблица, содержащая x
а также .
)
Я думал, что одно из следующего сделает трюк...
library(rvest)
library(tidyverse)
"https://international.ipums.org/international-action/variables/MIGYRSBR#codes_section" %>%
read_html() %>%
html_table()
"https://international.ipums.org/international-action/variables/MIGYRSBR#codes_section" %>%
read_html() %>%
html_nodes(".variablesList , #ui-id-1")
... но ничего полезного не возвращается. Я посмотрел на источник HTML-файла. Я думаю, что веб-сайт использует JavaScript для создания таблицы? Значит ли это, что невозможно получить стол?
Примечание: я не могу установить RSelenium на свой офисный компьютер
2 ответа
Я не видел нет robots.txt
ни T&C, но я прочитал (довольно устрашающее) "ЗАЯВЛЕНИЕ НА ИСПОЛЬЗОВАНИЕ ОГРАНИЧЕННЫХ МИКРОДАННЫХ" (я забыл, что у меня есть учетная запись, которая может получить доступ к IPUMS, хотя я не помню, чтобы когда-либо использовал ее). Я впечатлен их желанием зарегистрировать важность потенциально чувствительной природы их данных перед загрузкой.
Поскольку в этих метаданных нет "микроданных" (кажется, что метаданные предоставлены, чтобы помочь людям решить, какие элементы данных они могут выбрать), и поскольку их получение и использование не нарушает ни одно из заявленных ограничений, следующее должно быть в порядке., Если представитель IPUMS увидит это и не согласится, я с удовольствием удалю ответ и попрошу администраторов SO также действительно удалить его (для тех, кто не знает, люди с достаточно высоким представителем могут видеть удаленные ответы).
Теперь вам не нужны Selenium или Splash для этого, но вам нужно будет выполнить некоторую постобработку данных, полученных с помощью приведенного ниже кода.
Данные, которые создают таблицы метаданных, находятся в двоичном объекте javascript в <script>
тег (используйте "View Source", чтобы увидеть его, он понадобится вам позже). Мы можем использовать некоторые строки и пакет V8, чтобы получить его:
library(V8)
library(rvest)
library(jsonlite)
library(stringi)
pg <- read_html("https://international.ipums.org/international-action/variables/MIGYRSBR#codes_section")
html_nodes(pg, xpath=".//script[contains(., 'Less than')]") %>%
html_text() %>%
stri_split_lines() %>%
.[[1]] -> js_lines
idx <- which(stri_detect_fixed(js_lines, '$(document).ready(function() {')) - 1
Это находит цель <script>
element, получает содержимое, преобразует его в строки и находит первую строку, которая не является данными. Мы можем извлечь только код javascript с данными, так как движок V8 в R не является полноценным браузером и не может выполнить код jQuery после него.
Теперь мы создаем "контекст V8", извлекаем код и выполняем его в указанном контексте V8 и возвращаем его обратно:
ctx <- v8()
ctx$eval(paste0(js_lines[1:idx], collapse="\n"))
code_data <- ctx$get("codeData")
str(code_data)
## List of 14
## $ jsonPath : chr "/international-action/frequencies/MIGYRSBR"
## $ samples :'data.frame': 6 obs. of 2 variables:
## ..$ name: chr [1:6] "br1960a" "br1970a" "br1980a" "br1991a" ...
## ..$ id : int [1:6] 2416 2417 2418 2419 2420 2651
## $ categories :'data.frame': 100 obs. of 5 variables:
## ..$ id : int [1:100] 4725113 4725114 4725115 4725116 4725117 4725118 4725119 4725120 4725121 4725122 ...
## ..$ label : chr [1:100] "Less than 1 year" "1" "2" "3" ...
## ..$ indent : int [1:100] 0 0 0 0 0 0 0 0 0 0 ...
## ..$ code : chr [1:100] "00" "01" "02" "03" ...
## ..$ general: logi [1:100] FALSE FALSE FALSE FALSE FALSE FALSE ...
## $ longSamplesHeader : chr "<tr class=\"fullHeader grayHeader\">\n\n <th class=\"codesColumn\">Code</th>\n <th class=\"la"| __truncated__
## $ samplesHeader : chr "\n<tr class=\"fullHeader grayHeader\">\n <th class=\"codesColumn\">Code</th>\n <th class=\"labelColum"| __truncated__
## $ showCounts : logi FALSE
## $ generalWidth : int 2
## $ width : int 2
## $ interval : int 25
## $ isGeneral : logi FALSE
## $ frequencyType : NULL
## $ project_uses_survey_groups: logi FALSE
## $ variables_show_tab_1 : chr ""
## $ header_type : chr "short"
jsonPath
Компонент предполагает, что он использует больше данных при построении таблиц кодов и частот, поэтому мы также можем получить их:
code_json <- fromJSON(sprintf("https://international.ipums.org%s", code_data$jsonPath))
str(code_json, 1)
## List of 6
## $ 2416:List of 100
## $ 2417:List of 100
## $ 2418:List of 100
## $ 2419:List of 100
## $ 2420:List of 100
## $ 2651:List of 100
Эти "Списки 100" - это 100 номеров каждый.
Вам нужно будет посмотреть код в "View Source" (как предложено выше), чтобы увидеть, как вы можете использовать эти два бита данных для воссоздания таблицы метаданных.
Я думаю, что вам лучше пойти по пути, которым @alistaire начал вас, но следуйте ему полностью. Я не видел вопросов о получении "кодов и частот" или "метаданных" (таких как этот) на форуме ( http://answers.popdata.org/) и прочитал, по крайней мере, в 5 местах, которые сотрудники IPUMS читают и отвечают на вопросы на форумах, а также на их адрес электронной почты: ipums@umn.edu
,
Они, очевидно, имеют эти метаданные где-то в электронном виде и, вероятно, могут дать вам полный дамп для всех продуктов данных, чтобы избежать дальнейшей очистки (что, я думаю, ваша цель, так как я не могу представить сценарий, когда кто-то захочет пройти через эту проблему для одна выдержка).
См. Выше комментарий о чистке, но в случае, если это полезно, мы только что выпустили пакет ipumsr, который немного упрощает использование метаданных IPUMS в R.
Если вы делаете выписку с MIGYRSBR
в нем, а затем загрузите DDI (который доступен еще до того, как появятся полные микроданные), вы можете получить таблицу кодов с помощью команды:
# install.packages("ipumsr")
library(ipumsr)
ddi <- read_ipums_ddi("ipumsi_00020.xml")
ipums_val_labels(ddi, "MIGYRSBR")
#> # A tibble: 7 x 2
#> val lbl
#> <dbl> <chr>
#> 1 0 Less than 1 year
#> 2 6 6 (6 to 10 1960-70, 6 to 9 1980)
#> 3 10 10 (10+ 1980)
#> 4 11 11 (11+ 1960-70)
#> 5 97 97+
#> 6 98 Unknown
#> 7 99 NIU (not in universe)
Или вы можете загрузить полный набор данных, и метки значений будут прикреплены как labelled
векторы классов (из рая). Смотрите виньетки с метками значений для более подробной информации.
data <- read_ipums_micro(ddi, verbose = FALSE)
data$MIGYRSBR <- as_factor(data$MIGYRSBR)
table(data$MIGYRSBR)
#>
#> Less than 1 year 1
#> 123862 65529
#> 2 3
#> 77190 59908
#> 4 5
#> 44748 49590
#> 6 (6 to 10 1960-70, 6 to 9 1980) 10 (10+ 1980)
#> 185220 0
#> 11 (11+ 1960-70) 97+
#> 318097 0
#> Unknown NIU (not in universe)
#> 6459 2070836
Обратите внимание, что один только DDI не будет иметь доступность / частоты, которые есть в сети, вам нужно будет рассчитать их по данным.