web抓取使用JavaScript生成的表格

时间:2017-10-16 04:57:46

标签: javascript r web-scraping rvest

我正试图从this website上的代码标签(包含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 个答案:

答案 0 :(得分:3)

我没有看到robots.txt也没有看到T& C但我 读了(相当令人生畏)“申请使用受限制的MICRODATA”(我忘了我有一个可以访问的帐户IPUMS虽然我不记得曾经使用它)。我对他们希望在下载之前预先记录其数据潜在敏感性的重要性印象深刻。

由于此元数据中没有“微数据”(似乎提供了元数据以帮助人们决定他们可以选择哪些数据元素),并且因为获取&使用它不违反任何规定的限制,以下应该可以。如果IPUMS的代表看到这一点并且不同意,我很乐意删除答案并要求SO管理员真的删除它(对于那些不知道的人) ,人们足够高的代表可以看到删除的答案)。

现在,您不需要Selenium或Splash,但您需要对以下代码检索到的数据进行一些后处理。

构建元数据表的数据位于<script>标记的javascript blob中(使用“查看源”查看它,稍后您将需要它)。我们可以使用一些字符串munging&amp;得到它的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>元素,获取内容,将其转换为行并查找不是数据的第一行。我们只能用数据提取javascript代码,因为R中的V8引擎不是一个完整的浏览器,并且不能在它之后执行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个数字。

您需要查看“查看源代码”中的代码(如上所述),以了解如何使用这两位数据重新创建元数据表。

认为你最好跟随@alistaire启动你的路径,但完全按照 。我在论坛(http://answers.popdata.org/)中没有看到关于获取“代码和频率”或“元数据”(例如这个)的问题,并且至少在5个地方读取了IPUMS工作人员在论坛中阅读和回答的问题以及在他们的信息电子邮件地址:ipums@umn.edu

他们显然在某个地方以电子方式提供这些元数据,可能会让你在所有数据产品中完全转储它,以避免进一步刮擦(我的猜测是你的目标,因为我无法想象一个人想要通过的场景一个提取物的麻烦。)

答案 1 :(得分:1)

请参阅上面有关抓取的评论,但如果它有用,我们刚刚发布了ipumsr package,这使得在R中使用IPUMS元数据更加容易。

如果您使用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类向量(来自避风港)。有关详细信息,请参阅value-labels vignette

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不具备网络上的可用性/频率,您需要进行计算 来自数据的那些。