【问题标题】:Scraping a JavaScript object and converting to JSON within R/Rvest在 R/Rvest 中抓取 JavaScript 对象并转换为 JSON
【发布时间】:2017-10-19 19:19:21
【问题描述】:

我正在抓取以下网站:https://www.banorte.com/wps/portal/ixe/Home/indicadores/tipo-de-cambio

我正在尝试通过 rvest 包将货币汇率表放入 R 数据框中,但该表本身是在 HTML 代码中的 JavaScript 变量中配置的。

我找到了相关的 CSS 选择器,现在我有了这个:

library(rvest)    
banorte <- "https://www.banorte.com/wps/portal/ixe/Home/indicadores/tipo-de-cambio/" %>%
      read_html() %>%
      html_nodes('#indicadores_financieros_wrapper > script:nth-child(2)')

我的输出现在是以下 JavaScript 脚本,作为 XML 节点集:

<script>
$(document).ready(function(){
    var valor = '{"tablaDivisas":[{"nombreDivisas":"FRANCO SUIZO","compra":"18.60","venta":"19.45"}, {"nombreDivisas":"LIBRA ESTERLINA","compra":"24.20","venta":"25.15"}, {"nombreDivisas":"YEN JAPONES","compra":"0.1635","venta":"0.171"}, {"nombreDivisas":"CORONA SUECA","compra":"2.15","venta":"2.45"}, {"nombreDivisas":"DOLAR CANADA","compra":"14.50","venta":"15.35"}, {"nombreDivisas":"EURO","compra":"21.75","venta":"22.60"}], "tablaDolar":[{"nombreDolar":"VENTANILLA","compra":"17.73","venta":"19.15"}]}';
    if(valor != '{}'){
        var objJSON = eval("(" + valor + ")");
        var tabla="<tbody>";
        for ( var i = 0; i < objJSON["tablaDolar"].length; i++) {
            tabla+= "<tr>";
            tabla+= "<td>" + objJSON["tablaDolar"][i].nombreDolar + "</td>";
            tabla+= "<td>$" + objJSON["tablaDolar"][i].compra + "</td>";
            tabla+= "<td>$" + objJSON["tablaDolar"][i].venta + "</td>";
            tabla+= "</tr>";
        }
        tabla+= "</tbody>";
        $("#tablaDolar").append(tabla);
        var tabla2="";
        for ( var i = 0; i < objJSON["tablaDivisas"].length; i++) {
            tabla2+= "<tr>";
            tabla2+= "<td>" + objJSON["tablaDivisas"][i].nombreDivisas + "</td>";
            tabla2+= "<td>$" + objJSON["tablaDivisas"][i].compra + "</td>";
            tabla2+= "<td>$" + objJSON["tablaDivisas"][i].venta + "</td>";
            tabla2+= "</tr>";
        }
        tabla2+= "</tbody>";
        $("#tablaDivisas").append(tabla2);
    }
    bmnIndicadoresResponsivoInstance.cloneResponsive(0);
});
</script>

我的问题是,如何删除几乎所有内容(所有 JavaScript 函数/运算符)以仅获取此数据,并最终将其转换为 JSON 表,如下所示:

{"tablaDivisas":[{"nombreDivisas":"FRANCO SUIZO","compra":"18.60","venta":"19.45"},
{"nombreDivisas":"LIBRA ESTERLINA","compra":"24.20","venta":"25.15"},
{"nombreDivisas":"YEN JAPONES","compra":"0.1635","venta":"0.171"}, 
{"nombreDivisas":"CORONA SUECA","compra":"2.15","venta":"2.45"}, 
{"nombreDivisas":"DOLAR CANADA","compra":"14.50","venta":"15.35"}, 
{"nombreDivisas":"EURO","compra":"21.75","venta":"22.60"}],
"tablaDolar":[{"nombreDolar":"VENTANILLA","compra":"17.73","venta":"19.15"}]}

换句话说,我需要使用 R 从 JS 脚本中提取“valor”变量。

由于某种原因,我无法在 R 中完成这一切(无需将变量导出为外部 .txt 文件,然后使用子字符串)

【问题讨论】:

    标签: json r rvest


    【解决方案1】:

    你可以这样做:

    library(rvest)    
    banorte <- "https://www.banorte.com/wps/portal/ixe/Home/indicadores/tipo-de-cambio/" %>%
        read_html() %>%
        html_nodes('#indicadores_financieros_wrapper > script:nth-child(2)') %>%
        as_list()
    
    banorte_vec <- strsplit(banorte[[c(1,1)]],"\r\n")[[1]]
    valor <- grep("valor = ", banorte_vec, value = T)
    valor <- gsub("\tvar valor = ","",valor)
    valor <- gsub("';$","",valor)
    valor <- gsub("^'","",valor)
    
    library(jsonlite)
    result <- fromJSON(valor)
    result
    
    $tablaDivisas
      nombreDivisas compra venta
    1    FRANCO SUIZO  18.60 19.45
    2 LIBRA ESTERLINA  24.20 25.15
    3     YEN JAPONES 0.1635 0.171
    4    CORONA SUECA   2.15  2.45
    5    DOLAR CANADA  14.50 15.35
    6            EURO  21.75 22.60
    
    $tablaDolar
      nombreDolar compra venta
    1  VENTANILLA  17.73 19.15
    

    【讨论】:

      【解决方案2】:

      绝对是一个更重量级的答案,但可以概括为其他更棘手的“javascript问题”。

      library(rvest)
      library(stringi)
      library(V8)
      library(tidyverse)
      
      banorte <- "https://www.banorte.com/wps/portal/ixe/Home/indicadores/tipo-de-cambio/" %>%
            read_html() %>%
            html_nodes('#indicadores_financieros_wrapper > script:nth-child(2)')
      

      我们将设置一个 javascript V8 上下文:

      ctx <- v8()
      

      然后:

      • 获取&lt;script&gt; 内容
      • 把它分成几行
      • 将其转换为纯字符向量
      • 去除杂物
      • 评估 javascript

      还不错:

      html_text(banorte) %>% 
        stri_split_lines() %>% 
        flatten_chr() %>% 
        keep(stri_detect_regex, "^\tvar") %>% 
        ctx$eval()
      

      由于 javascript 是 JSON 字符串,我们在 R 与 V8 中进行 eval:

      jsonlite::fromJSON(ctx$get("valor"))
      ## $tablaDivisas
      ##     nombreDivisas compra venta
      ## 1    FRANCO SUIZO  18.60 19.45
      ## 2 LIBRA ESTERLINA  24.20 25.15
      ## 3     YEN JAPONES 0.1635 0.171
      ## 4    CORONA SUECA   2.15  2.45
      ## 5    DOLAR CANADA  14.50 15.35
      ## 6            EURO  21.75 22.60
      ## 
      ## $tablaDolar
      ##   nombreDolar compra venta
      ## 1  VENTANILLA  17.73 19.15
      

      如果在 javascript 中有其他有用的处理,这将更好地概括。

      注意:我的 Chrome 测试版频道中的谷歌翻译没有很好地翻译网站,但我认为你非常接近违反“Términos Legales”页面上第 6 项的精神,但在我能翻译之前我不能完全告诉。什么时候/如果可以的话,我会删除这个。

      【讨论】:

      • 我试过了,但我最终得到了一个空的全局环境。 Javascript 让我发疯!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-15
      • 2019-05-31
      • 2017-06-16
      • 2020-01-07
      • 1970-01-01
      • 2016-09-23
      • 1970-01-01
      相关资源
      最近更新 更多