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')