Raspado de tabla dinámica en R

shazz

Estoy atrapado en un simple web scrape. Mi objetivo es raspar Morningstar.com para recuperar la educación de los gerentes asociados a un nombre de fondo.

En primer lugar, déjeme decirle que no estoy familiarizado en absoluto con esta operación. Sin embargo, hice todo lo posible para proporcionar algo de código.

Por ejemplo, considere la siguiente página web http://financials.morningstar.com/fund/management.html?t=AALGX®ion=usa&culture=en_US

El problema es que la página carga dinámicamente la sección a la que me dirijo, por lo que en realidad no es arrastrada por read_html ()

Entonces lo que hice fue acceder a los datos cargados en mi sección de interés.

Específicamente, hice:

# edit: added packages required
library(xml2)
library(rvest)
library(stringi)

# original code
tmp_url <- "http://financials.morningstar.com/fund/management.html?t=AALGX&region=usa&culture=en_US"
pg <- read_html(tmp_url)
tmp <- length(html_nodes(pg, xpath=".//script[contains(., 'function loadManagerInfo()')]"))
html_nodes(pg, xpath=".//script[contains(., 'function loadManagerInfo()')]") %>% 
      html_text() %>% 
      stri_split_lines() %>% 
      .[[1]] -> js_lines

    idx <- which(stri_detect_fixed(js_lines, '\t\t\"//financials.morningstar.com/oprn/c-managers.action?&t='))
    start <- nchar("\t\t\"//financials.morningstar.com/oprn/c-managers.action?&t=")+1
    id <- substr(js_lines[idx],start, start+9)

tab <- read_html(paste0("http://financials.morningstar.com/oprn/c-managers.action?&t=",id,"&region=usa&culture=en-US&cur=&callback=jsonp1523529017966&_=1523529019244"), options = "HUGE")

La pestaña del objeto contiene la información que necesito.

Lo que necesito hacer ahora es crear un marco de datos que asocie al nombre de cada gerente, su educación de gerente. Podría intentar hacer esto transformando mi objeto en una cadena, luego extrayendo los caracteres que siguen a la palabra "Educación". Sin embargo, esto parece extremadamente ineficiente.

Me preguntaba si alguien puede proporcionar alguna orientación.

Petermeissner

Esto realmente es un desastre: un buen trabajo para obtener los enlaces y descargar la información.

Hurgando mucho y tomando varios desvíos, esto es lo mejor que pude encontrar:

Limpiar

Primero hay algo de limpieza que hacer. En lugar de descargar y analizar directamente el documento en un solo paso, haremos lo siguiente:

  1. descargar el documento como texto
  2. limpia un poco el texto para obtener el JSON
  3. analizar el JSON
  4. extraer el elemento HTML
  5. haz un poco más de limpieza
  6. finalmente analizar el HTML

url <- 
  paste0(
    "http://financials.morningstar.com/oprn/c-managers.action?&t=",
    id,
    "&region=usa&culture=en-US&cur=&callback=jsonp1523529017966&_=1523529019244"
  )

txt <- 
  readLines(url, warn = FALSE)

json <- 
  txt %>% 
  gsub("^jsonp\\d+\\(", "", .) %>% 
  gsub("\\)$", "", .)

json_parsed <- 
  jsonlite::fromJSON(json) 

html_clean <- 
  json_parsed$html %>% 
  gsub("\t", "", .) 

html_parsed <- 
  read_html(html_clean)   

Primera ronda de extracción de nodos

A continuación, usamos algunos trucos de extracción de nodos de magia negra. Básicamente, el truco es el siguiente: si tenemos un conjunto de nodos (lo que obtienes al usar html_nodes), podemos usar más consultas XPath para profundizar.

El primer conjunto de nodos ( cvs) captura la ruta básica a las entradas de CV en la tabla.

El segundo conjunto de nodos ( info_tmp) profundiza un poco más para obtener la parte de las entradas del CV donde se almacena más información ("Otros activos administrados", "Educación", ... etc.).

cvs <- 
  html_parsed %>% 
  html_nodes(xpath = "/html/body/table/tbody/tr[not(@align='left')]")

info_tmp <- 
  cvs %>% 
  html_nodes(xpath = "td/table/tbody")

Construyendo datos.Frame 1

Hay un pequeño problema con la mesa. Cada entrada de CV vive en su propia fila de la tabla. Para name, from, toy descriptionsiempre hay exactamente un artículo por la entrada CV pero para "Otros activos gestionados", "Educación", etc ... esto no es cierto. Por tanto, la extracción de información se realiza en dos partes.

df <- 
  cvs %>% 
  lapply(
    FUN = 
      function(x){
        tmp <- 
          x %>% 
          html_nodes(xpath = "th") %>% 
          html_text() %>% 
          gsub("  +", "", .)

        data.frame(
          name = stri_extract(tmp, regex = "[. \\w]+"),
          from = stri_extract(tmp, regex = "\\d{2}/\\d{2}/\\d{4}"),
          to   = stri_extract(tmp, regex = "\\d{2}/\\d{2}/\\d{4}")
        )
      }
  ) %>% 
  do.call(rbind, .)

df$description <- 
  info_tmp %>% 
  html_nodes(xpath = "tr[1]/td[1]") %>% 
  html_text()

df$cv_id <- seq_len(nrow(df))

Construyendo datos.Frame 2

Ahora algunos trucos más para los nodos html ... Si usamos html_nodes()el conjunto de resultados de html_nodes()obtenemos todos los nodos coincidentes y ninguno de los nodos coincidentes. Esto es un problema ya que podríamos obtener 1, 0 o múltiples nodos por nodo de conjunto de nodos básicamente destruyendo cualquier información sobre el origen de esos nodos recién seleccionados.

Sin embargo, hay una solución: podemos usar lapply para consultar cada elemento de un conjunto de nodos independientemente de los demás y, por lo tanto, preservar la información sobre la estructura original.

extract_key_value_pairs <- 
  function(i, info_tmp){

    cv_id <-
      seq_along(info_tmp)

    key <-
      lapply(
        info_tmp, 
        function(x){
          tmp <- 
            x %>% 
            html_nodes(xpath = paste0("tr[",i,"]/td[1]")) %>% 
            html_text() 
          if ( length(tmp) == 0 ) {
            return("")
          }else{
            return(tmp)
          }
        }
      )

    value <-
      lapply(
        info_tmp, 
        function(x){
          tmp <- 
            x %>% 
            html_nodes(xpath = paste0("tr[",i,"]/td[2]")) %>% 
            html_text() %>% 
            stri_trim_both() %>% 
            stri_split(fixed = "\n") %>% 
            lapply(X = ., stri_trim_both)

          if ( length(tmp) == 0 ) {
            return("")
          }else{
            return(unlist(tmp))
          }
        }
      )
    df <- 
      mapply(
        cv_id = cv_id, 
        key   = key, 
        value = value,
        FUN = 
          function(cv_id, key, value){
            data.frame(
              cv_id = cv_id,
              key   = key,
              value = value
            )
          },
        SIMPLIFY = FALSE
      ) %>% 
      do.call(rbind, .)

    df[df$key != "",]
  }

df2 <- 
  lapply(
    X        = c(3, 5, 7),
    FUN      = extract_key_value_pairs,
    info_tmp = info_tmp
  ) %>% 
  do.call(rbind, .)

Resultados

df 
##                   name       from         to    description cv_id
## 1       Kurt J. Lauber 03/20/2013 03/20/2013 Mr. Lauber ...     1
## 2       Noah J. Monsen 02/28/2018 02/28/2018 Mr. Monsen ...     2
## 3        Lauri Brunner 09/30/2018 09/30/2018 Ms. Brunne ...     3
## 4    Darren M. Bagwell 02/29/2016 02/29/2016 Darren M.  ...     4
## 5     David C. Francis 10/07/2011 10/07/2011 Francis is ...     5
## 6    Michael A. Binger 04/14/2010 04/14/2010 Binger has ...     6
## 7      David E. Heupel 04/14/2010 04/14/2010 Mr. Heupel ...     7
## 8      Matthew D. Finn 03/30/2007 03/30/2007 Mr. Finn h ...     8
## 9         Scott Vergin 03/30/2007 03/30/2007 Vergin has ...     9
## 10 Frederick L. Plautz 11/01/1995 11/01/1995 Plautz has ...    10
## 11    Clyde E. Bartter 01/01/1994 01/01/1994 Bartter is ...    11
## 12    Wayne C. Stevens 01/01/1994 01/01/1994 Stevens is ...    12
## 13      Julian C. Ball 07/16/1987 07/16/1987 Ball is a  ...    13


df2
## cv_id                  key                                   value
##     1 Other Assets Managed                                        
##     2 Other Assets Managed                                        
##     3 Other Assets Managed                                        
##     4        Certification                                     CFA
##     4 Other Assets Managed                                        
##     5        Certification                                     CFA
##     5            Education   M.B.A. University of Pittsburgh, 1978
##     5            Education     B.A. University of Pittsburgh, 1977
##     5 Other Assets Managed                                        
##     6        Certification                                     CFA
##     6            Education    M.B.A. University of Minnesota, 1991
##     6            Education      B.S. University of Minnesota, 1987
##     6 Other Assets Managed                                        
##     7 Other Assets Managed                                        
##     8        Certification                                     CFA
##     8            Education   B.A. University of Pennsylvania, 1984
##     8            Education     M.B.A. University of Michigan, 1990
##     8 Other Assets Managed                                        
##     9        Certification                                     CFA
##     9            Education    M.B.A. University of Minnesota, 1980
##     9            Education             B.A. St. Olaf College, 1976
##     9 Other Assets Managed                                        
##    10            Education      M.S. University of Wisconsin, 1981
##    10            Education    B.B.A. University of Wisconsin, 1979
##    10 Other Assets Managed                                        
##    11        Certification                                     CFA
##    11            Education M.B.A. Western Reserve University, 1964
##    11            Education      B.A. Baldwin-Wallace College, 1953
##    11 Other Assets Managed                                        
##    12        Certification                                     CFA
##    12            Education         M.B.A. University of Wisconsin,
##    12            Education             B.B.A. University of Miami,
##    12 Other Assets Managed                                        
##    13        Certification                                     CFA
##    13            Education        B.A. Kent State University, 1974
##    13            Education   J.D. Cleveland State University, 1984
##    13 Other Assets Managed                                        

Este artículo se recopila de Internet, indique la fuente cuando se vuelva a imprimir.

En caso de infracción, por favor [email protected] Eliminar

Editado en
0

Déjame decir algunas palabras

0Comentarios
Iniciar sesiónRevisión de participación posterior

Artículos relacionados