【问题标题】:How do I specify the range to be executed in this for loop (R)?如何指定要在此 for 循环 (R) 中执行的范围?
【发布时间】:2020-12-14 08:57:14
【问题描述】:

我正在写一个用于抓取歌词的小包。现在的问题是它的行为非常笨拙,无法控制。我希望能够在执行抓取的 for 循环中指定要影响的范围。

我有两个功能,一个是显示歌曲列表,另一个是抓取它们:

songlist <- function(x) {
  url <- paste0("https://www.azlyrics.com/", substring(x, 1, 1),"/",x, ".html")
  page <- url
  songs <- page %>%
    xml2::read_html() %>%
    rvest::html_nodes(xpath = "/html/body/div[2]/div/div[2]/div[4]/div/a") %>%
    rvest::html_text() %>%
    as.data.frame()


  chart <- cbind(songs)
  names(chart) <- c("Songs")
  chart <- tibble::as_tibble(chart)
  return(chart)
}

这给了我一个像这样的小标题:

  Songs                 
   <chr>                 
 1 Meet Me In The Hallway
 2 Sign Of The Times     
 3 Carolina              
 4 Two Ghosts            
 5 Sweet Creature        
 6 Only Angel            
 7 Kiwi                  
 8 Ever Since New York   
 9 Woman                

另一个名为songscrape() 的函数接受一个字符串参数,用于构建网址并从该艺术家那里抓取所有歌曲。它里面有一个songlist() 的副本,它会为 Like so 生成 url:

songscrape <- function(x) {
  url <- paste0("https://www.azlyrics.com/", substring(x, 1, 1),"/",x, ".html")
  artist <- x

  SongsListScrapper <- function(x) {
    page <- x
    songs <- page %>%
      xml2::read_html() %>%
      rvest::html_nodes(xpath = "/html/body/div[2]/div/div[2]/div[4]/div/a") %>%
      rvest::html_text() %>%
      as.data.frame()


    chart <- cbind(songs)
    names(chart) <- c("Songs")
    chart <- tibble::as_tibble(chart)
    return(chart)
  }

  SongsList <- purrr::map_df(url, SongsListScrapper)
  SongsList

  SongsList %<>%
    dplyr::mutate(
      Songs = as.character(Songs)
      ,Songs = gsub("[[:punct:]]", "", Songs)
      ,Songs = tolower(Songs)
      ,Songs = gsub(" ", "", Songs)
    )

  SongsList$Songs

  #Scrape Lyrics

  wipe_html <- function(str_html) {
    gsub("<.*?>", "", str_html)
  }

  lyrics <- c()

  for(i in seq_along(SongsList$Songs)) {
    for_url_name <- SongsList$Songs[i]

    #clean name
    for_url_name <- tolower(gsub("[[:punct:]]\\s", "", for_url_name))
    #create url
    paste_url <- paste0("https://www.azlyrics.com/lyrics/", artist,"/", for_url_name, ".html")
    tryCatch( {
    #open connection to url
    for_html_code <- xml2::read_html(paste_url)
    for_lyrics <- rvest::html_node(for_html_code, xpath = "/html/body/div[2]/div/div[2]/div[5]")
  }

如您所见,for 循环显示for(i in seq_along(SongsList$Songs)),基本上表示所有歌曲。是否可以改为输入范围。就像我最多选择 5 首歌曲或从第 10 首歌曲到第 15 首歌曲(基于 tibble 中的数字)。

所以更新后的函数调用看起来像 songscrape("ironwine", from = 5, to = 15)songscrape("ironwine", n = 20) #first 20 songs

我该怎么做?

【问题讨论】:

    标签: r loops for-loop


    【解决方案1】:

    使用函数重载解决了这个问题!如果您注意到,循环数由SongList 数据帧决定。如果我们按适当的数量对其进行子集化,则应该正确完成循环。我不会发布完整的代码,但这里是要点:

    songscrape <- function(x,y,z) {
    
    #If only the string argument is passed
    if(missing(y) && missing(x)) {
         y == FALSE 
                       }
    #if only one numeric argument is passed
    if(missing(z)) {
         z == FALSE   
                       }
    
    #Now just modify the to fit the numbers passed. 
    
    if(y == FALSE) {
    
          #User wants all songs
    
         } else if (z == FALSE) {
    
          #User wants top N songs given by the songlist() function. 
          #Slice the SongList data frame by y value
    
          SongList <- SongList %>% slice(1:y)
    
         } else {
    
    
          #User wants between a range, so slice between y and z.
          SongList <- SongList %>% slice(y:z)
    
    }
    

    由于for loop 使用SongList 数据帧来运行,您唯一需要做的就是适当地对其进行切片,它会在这些值之间运行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-12
      • 2021-11-11
      • 1970-01-01
      • 1970-01-01
      • 2019-01-12
      • 1970-01-01
      相关资源
      最近更新 更多