You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

geniusr包get_lyrics系列函数报错求助:替换长度为零等问题

问题描述

使用geniusr包的get_lyrics_*系列函数时持续报错,其他函数运行正常。最初报错:

Error in section_artist[is.na(section_artist)] <- artist : replacement has length zero

尝试调用get_lyrics_search("Rihanna", "Stay")时,又出现列大小不兼容错误:

Error in `tibble()`:
! Tibble columns must have compatible sizes.
• Size 34: Existing data.
• Size 0: Column `artist_name`.
ℹ Only values of size one are recycled.

已安装并加载rvest包,尝试过旧修复补丁但无效,自定义的get_lyrics函数代码如下:

library(tidyverse)
library(geniusr)                        
library(tidytext)
library(readr)
library(rvest)

#genius api token
genius_token(force = TRUE)
(...)

get_lyrics <- function (session) {
  lyrics <-  session %>% html_nodes(xpath = '//div[contains(@class, "Lyrics__Container")]')
  song <-  session %>% html_nodes(xpath = '//span[contains(@class, "SongVariantdesktop__")]') %>% html_text(trim = TRUE)
  artist <-  session %>% html_nodes(xpath = '//a[contains(@class, "SongVariantdesktop__Artist")]') %>% html_text(trim = TRUE)
  xml_find_all(lyrics, ".//br") %>% xml_add_sibling("p", "\n")
  xml_find_all(lyrics, ".//br") %>% xml_remove()
  lyrics <- html_text(lyrics, trim = TRUE)
  lyrics <- unlist(strsplit(lyrics, split = "\n"))
  lyrics <- grep(pattern = "[[:alnum:]]", lyrics, value = TRUE)
  if (is_empty(lyrics)) {
    return(tibble(line = NA, section_name = NA, section_artist = NA, 
                  song_name = song, artist_name = artist))
  }
  section_tags <- nchar(gsub(pattern = "\\[.*\\]", "", lyrics)) == 0
  sections <- geniusr:::repeat_before(lyrics, section_tags)
  sections <- gsub("\\[|\\]", "", sections)
  sections <- strsplit(sections, split = ": ", fixed = TRUE)
  section_name <- sapply(sections, "[", 1)
  section_artist <- sapply(sections, "[", 2)
  section_artist[is.na(section_artist)] <- artist
  tibble(line = lyrics[!section_tags], section_name = section_name[!section_tags], 
         section_artist = section_artist[!section_tags], song_name = song, 
         artist_name = artist)
}
assignInNamespace("get_lyrics", get_lyrics, "geniusr")
解决方案

问题根源是Genius网站页面结构更新,原xpath选择器无法匹配到艺术家和歌曲名元素,导致artist变量为空长度向量,进而引发替换错误和tibble列大小不兼容问题。以下是修复后的代码和关键修改点:

修复后的get_lyrics函数

get_lyrics <- function (session) {
  # 获取歌词容器
  lyrics <- session %>% html_nodes(xpath = '//div[contains(@class, "Lyrics__Container")]')
  
  # 适配新页面结构:提取歌曲名和艺术家
  song <- session %>% html_nodes(xpath = '//h1[contains(@class, "SongHeaderdesktop__Title")]') %>% 
    html_text(trim = TRUE)
  # 优先从艺术家链接提取,失败则从页面副标题提取
  artist <- session %>% html_nodes(xpath = '//a[contains(@class, "SongHeaderdesktop__Artist")]') %>% 
    html_text(trim = TRUE)
  if (length(artist) == 0) {
    artist <- session %>% html_nodes(xpath = '//span[contains(@class, "SongHeaderdesktop__Artist")]') %>% 
      html_text(trim = TRUE)
  }
  # 兜底:如果还是空,用默认值避免长度0
  if (length(artist) == 0) artist <- "Unknown Artist"
  if (length(song) == 0) song <- "Unknown Song"
  
  # 处理歌词换行
  xml_find_all(lyrics, ".//br") %>% xml_add_sibling("p", "\n")
  xml_find_all(lyrics, ".//br") %>% xml_remove()
  lyrics <- html_text(lyrics, trim = TRUE)
  lyrics <- unlist(strsplit(lyrics, split = "\n"))
  lyrics <- grep(pattern = "[[:alnum:]]", lyrics, value = TRUE)
  
  if (is_empty(lyrics)) {
    return(tibble(line = NA, section_name = NA, section_artist = NA, 
                  song_name = song, artist_name = artist))
  }
  
  section_tags <- nchar(gsub(pattern = "\\[.*\\]", "", lyrics)) == 0
  sections <- geniusr:::repeat_before(lyrics, section_tags)
  sections <- gsub("\\[|\\]", "", sections)
  sections <- strsplit(sections, split = ": ", fixed = TRUE)
  
  section_name <- sapply(sections, "[", 1)
  section_artist <- sapply(sections, "[", 2)
  
  # 确保替换时artist不为空长度
  if (length(artist) > 0) {
    section_artist[is.na(section_artist)] <- artist
  } else {
    section_artist[is.na(section_artist)] <- "Unknown Artist"
  }
  
  # 构建tibble,确保所有列长度匹配
  tibble(
    line = lyrics[!section_tags], 
    section_name = section_name[!section_tags], 
    section_artist = section_artist[!section_tags], 
    song_name = rep(song, length(lyrics[!section_tags])), 
    artist_name = rep(artist, length(lyrics[!section_tags]))
  )
}
assignInNamespace("get_lyrics", get_lyrics, "geniusr")

关键修改说明

  1. 更新xpath选择器:针对Genius当前页面结构,替换了歌曲名和艺术家的xpath,优先从SongHeaderdesktop__Title和SongHeaderdesktop__Artist元素提取,适配最新页面布局。
  2. 兜底处理空值:当无法提取到艺术家或歌曲名时,设置默认值(如"Unknown Artist"),避免出现长度为0的向量。
  3. 安全替换NA值:在替换section_artist的NA值前,先检查artist是否有效,避免因artist为空导致的替换错误。
  4. 确保列长度匹配:使用rep()函数将song和artist重复到与歌词行数一致,解决tibble列大小不兼容的问题。

内容的提问来源于stack exchange,提问作者Troteritus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 23:04:54