Веб-просмотр таблиц, созданных с использованием 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 не будет иметь доступность / частоты, которые есть в сети, вам нужно будет рассчитать их по данным.

Другие вопросы по тегам