Scraping a stackoverflow

6 minute read


El ratón de biblioteca

Carl Spitzweg, El ratón de biblioteca (1850)

El código completo lo encontraras aquí


Hace poco me encontraba platicando con un amigo, se encuentra muy interesado por aprender a programar, y la pregunta natural es ¿Qué lenguaje debería de aprender? mi primer respuesta fue que en la ciencia de datos los mas demandados son Python y R, y era obvia para mi esta respuesta ya que al ser mi formación como economista mi primer puerta de entrada a la programación fue por R, sin embargo él no hablaba para algo especifico como la ciencia de datos.

En este articulo el autor analiza las preguntas mas populares de stackoverflow pagina que todos conocemos y si aun no lo haces faltara poco para que lo hagas.

De tal manera que este será un tutorial para entender como funciona el web scraping y observar que lenguajes son mas populares por el numero de preguntas en stackoverflow y ver de que manera se relacionan entre si los tags de preguntas.

Hora de ensuciarse las manos!

Estos son los paquete necesitaremos de igual manera usaremos un plugin de google chrome(también disponible para firefox)

library(tidyverse)
library(rvest)
library(dplyr)
library(tidygraph)

Visitemos la url https://stackoverflow.com/tags?page=1&tab=popular como podemos ver en esta url tiene un tag “page=1” el cual nos sirve para identificar la pagina en la que estamos y el tag “tab=popular” lo que nos indica que está ordenado del mas popular al menos popular para nuestro ejemplo solo tomaremos los 36 primeros ranks(cada pagina contiene 36 tags)

#guardamos la URL
url <- 'https://stackoverflow.com/tags?page=1&tab=popular'

SelectorGadget nos ayuda a encontrar el nombre del nodo que nos interesa para la extracción de la información, como podemos ver en la siguiente imagen, después de seleccionar el plugin es posible seleccionar el elemento que nos interesa para ver el nombre del nodo, primero veamos el nombre del nodo que indica el tag para después elegir el nodo que indica el número de preguntas para ese tag

Como vemos los nodos que nos importan son “.post-tag” y “.item-multiplier-count”

# nombre de los nodos en el archivo html que nos importan
node_name <- c('.post-tag','.item-multiplier-count')

Creamos la función info_extract la cual se encargara de extraer y convertir en un data frame la información de los nodos que busquemos

info_extract <- function(url,names,node_name) {

  #leemos la url
  webpage <- read_html(url)

  # ciclo for para cada nodo
  for (i in 1:length(node_name)) {
    #extraemos la información del nodo
    html <- html_nodes(webpage,node_name[i])
    #lo convertimos en texto
    name <- html_text(html)

    if(i==1){
      result <- name

    }else {
      result <- cbind(result,name)
    }
  }

  #lo convertimos en un dataframe
  result <- data.frame(result,stringsAsFactors = F)
  names(result) <- names
  result
}

Crearemos el data frame

# nombre de las columnas que crearemos
names <- c("name_topic","number_question")

extract <- info_extract(url,names,node_name)
head(extract)
##   name_topic number_question
## 1 javascript         1757628
## 2       java         1511400
## 3         c#         1283199
## 4        php         1260369
## 5    android         1171008
## 6     python         1106846

Creamos la función related_tags para obtener un data.frame con los tags que mas se relacionan a los tags populares

related_tags <- function(lenguaje) {
  # creamos esta bandera para identificar que es el primer ciclo for
  flag_first <- T
  for (i in lenguaje) {
    cat("----------------------\n",
        "Extrayendo: ",i,"\n",
        "======================\n")
    #en caso de que el nombre sea "c#" la url de stackoverflow la convierte en el tag
    # "c%223" lo mismo sucede con "c++" lo vuelve "c%2b%2b" por lo tanto haremos lo mismo
    i <- ifelse(i=="c#","c%23",i)
    i <- ifelse(i=="c++","c%2b%2b",i)

    # creamos la url con el nombre del tag
    url <- paste0('https://stackoverflow.com/questions/tagged/',i)
    webpage <- read_html(url)

    # buscamos el nombre de los lenguajes que mas se taggean con los tags populares
    rank_data_html <- html_nodes(webpage,'.js-gps-related-tags')
    character<- as.character(rank_data_html)
    strsplit <- strsplit(character," ")%>% unlist()

    # buscamos cuantas veces el tag secundario se asocia con el tag popular
    count_html <- html_nodes(webpage,'.item-multiplier-count')
    count <- html_text(count_html)

    #despues de separar buscamos en que filas se encuentran los tag que nos importan
    grep <- grep(paste0("/questions/tagged/",i),strsplit, value = T)
    grep <- gsub(paste0("href=\"/questions/tagged/",i,"+"),"",grep)
    grep <- gsub("\"","",grep)
    second_tag <- substr(grep,2,nchar(grep))
    popular <- rep(i,length(substr))
    cbind <-  cbind(popular,second_tag) %>% cbind(count)

    if(flag_first)  {
      related_tags <- cbind
      flag_first <- F
      }else {related_tags <- rbind(related_tags,cbind)}
  }

  related_tags <- related_tags %>%
    data.frame(stringsAsFactors = F)
  related_tags$count <-  related_tags$count %>%
    as.numeric()
  related_tags
}

Básicamente lo que haremos es visitar uno a uno el URL correspondiente a cada tag popular por ejemplo la URL del tag “Android” se compone de la siguiente manera https://stackoverflow.com/questions/tagged/android como vemos después de tagged/ se encuentra Android indicando la URL de interés.

En esta dirección los nodos que nos importan son “.item-multiplier-count” y “.js-gps-related-tags”, nos indican cuantas veces el tag secundario se ah tageado junto al tag popular, después creamos un data frame con la información anterior para cada uno de los tags populares, recorriendo uno a uno los 36 tags populares.

tabla_result <- related_tags(extract$name_topic)
tabla_result %>% head()
##      popular second_tag  count
## 1 javascript     jquery 523968
## 2 javascript       html 324333
## 3 javascript        css 149451
## 4 javascript  angularjs 116909
## 5 javascript        php 112939
## 6 javascript    node.js  95794

Ordenaremos de forma descendiente el conteo donde aparecen juntos el tag popular con el secundario y nos quedaremos con las primeras 150 filas de manera que sea mas cómodo el manejo de los datos

muestra <- tabla_result %>%
           arrange(desc(count)) %>%
           head(150)
library(htmlwidgets)
library(visNetwork)
library(tidygraph)

sources <- tabla_result %>%
  distinct(popular) %>%
  rename(label = popular)

destinations <- muestra %>%
  distinct(second_tag) %>%
  rename(label = second_tag)

nodes <- full_join(sources, destinations, by = "label")
#nodes
nodes <- nodes %>% rowid_to_column("id")
#nodes


per_route <- muestra %>%  
  group_by(popular, second_tag) %>%
  summarise(weight = sum(count)) %>%
  ungroup() %>% arrange(desc(popular )) %>%
  arrange(desc(weight ))

per_route
## # A tibble: 150 x 3
##    popular    second_tag weight
##    <chr>      <chr>       <dbl>
##  1 jquery     javascript 523968
##  2 javascript jquery     523968
##  3 html       css        346166
##  4 css        html       346166
##  5 javascript html       324333
##  6 html       javascript 324333
##  7 java       android    224994
##  8 android    java       224994
##  9 php        mysql      219014
## 10 mysql      php        219014
## # ... with 140 more rows
edges <- per_route %>%
  left_join(nodes, by = c("popular" = "label")) %>%
  rename(from = id)

edges <- edges %>%
  left_join(nodes, by = c("second_tag" = "label")) %>%
  rename(to = id)


edges <- select(edges, from, to, weight)
#edges




edges <- mutate(edges, width = weight/(max(weight)-min(weight))*10 )
visNetwork <- visNetwork(nodes, edges) %>%
  visIgraphLayout(layout = "layout_with_fr") %>%
  visEdges(arrows = "middle")

htmlwidgets::saveWidget(visNetwork,"visNetwork.html")

Después de ver las conexiones que existen entre los diferentes tags, vemos que JavaScript, JQuery, HTML y PHP son tecnologías de las mas populares y que se encuentran relacionadas con muchas tecnologías

También podemos ver como se agrupan las tecnologías como Android y java

Y hablando de ciencia de datos vemos como se relacionan Python con otras tecnologías, y al ser un lenguaje multipropósito es normal que la ciencia de datos no sea lo único a su alrededor, y mucho menos lo mas importante.

Y bueno ¿a todo esto donde se encuentra R?

ok… ok…. quizás no se encuentra relacionado a muchas tecnologías (al menos no en el volumen necesario para destacar en este análisis) como los tags anteriores, pero esto no significa que no sea popular ya que se encuentra dentro de los 36 mas tageados

Conclusiones

Sin duda la tecnología (en este caso el lenguaje) mas popular en stackoverflow es JavaScript lo cual lo reafirmamos con la gran cantidad de tecnologías que se asocian a esta.

El web scraping es realmente divertido, ya que puedes obtener información que esta ahí pero no a simple vista, basta adentrarse para encontrarla, estructurarla y analizarla.

Acontinuacion puedes analizar por ti mismo la red creada, hacer zoom, mover los nodos etc.

htmltools::includeHTML("./visNetwork.html")
visNetwork

Fuentes:

http://varianceexplained.org/r/year_data_scientist/ https://www.jessesadler.com/post/network-analysis-with-r/ https://www.analyticsvidhya.com/blog/2017/03/beginners-guide-on-web-scraping-in-r-using-rvest-with-hands-on-knowledge/

Updated: