How to make R repeat a request?

2

I'm trying to extract data from Vagalume through R, for that, I used the package "vagalumeR", and I took an example code from here:

The problem: when trying to extract the lyrics of certain artist's music I get an error, almost always, but not always, which makes me assume that the error is the result of API instability. so I'd like to know how to get R to repeat the request until the letter is actually extracted.

library(vagalumeR)
library(plyr)
library(tidyverse)
artist <- "portela"
song <- songNames(artist)
let <- ldply(map(song$song.id[1:62], lyrics, type = "id",
                 key = key), data.frame)
  

Error in if (cont $ mus [[1]] $ lang> 1) {: argument is of length zero

    
asked by anonymous 03.03.2018 / 20:01

1 answer

1

Try to get

The following solution is neither efficient nor elegant, but it does what you asked for.

lyrics2 <- function(x, type, key) {
  # Tenta pegar dados
  res <- try(lyrics(x, type = type, key = key))
  if (inherits(res, 'try-error')) { # verifica se houve erro
    cat('Um erro ocorreu com a música de id:', as.character(x), '\n')
    Sys.sleep(abs(rnorm(1, 2)))
    return(lyrics2(x, type, key)) # faz chamada recursiva
  }
  res # retorna resultado caso não haja erro
}

The idea of lyrics2 is basically trying to call the function and, if an error occurs, call this function that recursively rechecks the error ( lyrics2 ). This way it will stop calling only when there is no error in the request.

The try() function tries to execute the code within it but not in case an error occurs. In this case it returns an object with the 'try-error' class and with the error message.

If an error has occurred, the Sys.sleep() function sets the system to "sleep". The argument passed to it is the absolute value of a random number, which on average will be 2. The idea of doing this is to be "gentle" with the server.

It happens that the code is running endlessly (or at least for a long time) because there is some problem with the API in some IDs (like '3ade68b8g2009b0b3').

let2 <- map(song$song.id, lyrics2, type = "id", key = key)

Eliminate faults

For this reason, another option might be to try to run the code once and eliminate the flaws.

df_erro <- data.frame(
  id = 'erro', name = 'erro', song.id = 'erro',
  song = 'erro', language = NA_integer_, text = 'erro'
)
safe_lyrics <- safely(lyrics, otherwise = df_erro, FALSE)

The code above uses some of the concepts in the purrr package (already loaded in tidyverse ).

The first of these is the idea of a secure function. The safely() function returns the same function passed as the first argument, but with a modification: it will now return a result with two lists. The first list is called result and contains the result if everything happens well and the second one is called error and will contain the error message. The second argument passed is the result that should return in cases of error. It is useful for joining results later

The second is to use the map_df('result') function to map all lists that returns from the first map to extract the 'result' element from them and merge them into a data.frame .

let3 <- map(song$song.id, safe_lyrics, type = "id", key = key) %>% 
  map_df('result')

The above result returns a data.frame with 62 remarks, one for each Portela song. The errors return with the contents of df_erro and can be checked with which(let3$id == 'erro')

    
05.03.2018 / 04:48