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")
关键修改说明
- 更新xpath选择器:针对Genius当前页面结构,替换了歌曲名和艺术家的xpath,优先从
SongHeaderdesktop__Title和SongHeaderdesktop__Artist元素提取,适配最新页面布局。 - 兜底处理空值:当无法提取到艺术家或歌曲名时,设置默认值(如"Unknown Artist"),避免出现长度为0的向量。
- 安全替换NA值:在替换
section_artist的NA值前,先检查artist是否有效,避免因artist为空导致的替换错误。 - 确保列长度匹配:使用
rep()函数将song和artist重复到与歌词行数一致,解决tibble列大小不兼容的问题。
内容的提问来源于stack exchange,提问作者Troteritus
相关产品推荐
相关产品推荐

