【问题标题】:Extract hyperlink from Excel file in R从R中的Excel文件中提取超链接
【发布时间】:2022-03-11 00:53:41
【问题描述】:

如何在 Excel 中获取具有超链接文本的单元格并提取超链接部分?

【问题讨论】:

  • 是否只需要识别单元格是否包含超链接?
  • 你能读入文件并使用 gsub() 或变体来定位和提取超链接吗?
  • 使用xlsx,一旦你在调用getCells(…)之后有了类似于cells的变量,那么你可以做一个getCallValue设置encoding"unknown"然后使用其他各种 R 代码来测试它是否是超链接。
  • 我在快要出门的时候提交了这个问题。也许我可以做得更好。我知道哪一列包含超链接。当我阅读 Excel 文件时,我得到的只是文本,但我需要提取地址/URL。
  • 您可以使用来自this SO thread 的正则表达式来查找和提取几乎任何 URI/URL。

标签: r


【解决方案1】:

我发现了一种超复杂的提取超链接的方法:

library(XML)

# rename file to .zip
my.zip.file <- sub("xlsx", "zip", my.excel.file)
file.copy(from = my.excel.file, to = my.zip.file)

# unzip the file
unzip(my.zip.file)

# unzipping produces a bunch of files which we can read using the XML package
# assume sheet1 has our data
xml <- xmlParse("xl/worksheets/sheet1.xml")

# finally grab the hyperlinks
hyperlinks <- xpathApply(xml, "//x:hyperlink/@display", namespaces="x")

源自this blogpost

【讨论】:

  • (a) 很棒的发现; (b) 没有那么复杂。 RExcelXML 做了类似的事情。不要忘记将您自己的问题标记为已回答!
  • 从您的 cmets 可以清楚地看出您正在使用哪些软件包,但您仍应在答案中包含适当的序言( library(XML))。
  • 你是如何阅读你的excel文件的?
  • my.excel.file = "your_excel_file.xlsx" 那时他还没有读取 excel 文件,只是创建了一个与他的 excel 文件同名的字符向量,但使用 .zip作为文件扩展名。然后,他创建了其 excel 文件的副本,但该文件的扩展名为 .zip跨度>
【解决方案2】:

受上述@rrs 帖子的启发,我整理了一个函数来提取工作簿中的所有超链接,并带有参考(表格!A1 格式),您可以使用它在任何单元格中查找超链接。

**一些注释解释了下面的sn-p:**

-- 解压 excel 文件后,超链接存储在两个文件中,(a) xl/worksheets/sheet1.xml 和 xl/worksheets/_rels/sheet1.xml.res。虽然 xml 具有到 rId(关系 id?)表的单元格位置,但 xml.res 具有实际的 rId 和超链接表

-- 嵌入函数 read_relationships 解析 XML 并加入它们

-- temp_base_dir 用于承载文件操作

-- map_df 将所有选项卡中的超链接堆叠在一起

-- 输出数据框有 5 列。即 id(关系 id)、target(超链接)、ref(工作表中的单元格引用!A1 格式)、tab_idx(工作表索引)、tab(工作表名称)

片段:

library(tidyverse)
library(XML)
extract_hyperlinks_from_excel <- function(aExcelFile, aRefOutputFile = NULL){
  sheets <- readxl::excel_sheets(aExcelFile)
  
  read_relationships <- function(aSheetIndex){
    filename <- file.path(tmp_base_dir, 'xl', 'worksheets', '_rels', paste0('sheet', aSheetIndex, '.xml.rels'))    
    rel <- xmlParse(filename)
    rel <- xmlToList(rel)
    rel <- purrr::map_dfr(rel, as.list)
    rel <- rel[, c('Id', 'Target')]
    names(rel) <- c('id', 'target')
    if(nrow(rel) == 0){
      return(NULL)
    }
    
    filename <- file.path(tmp_base_dir, 'xl', 'worksheets', paste0('sheet', aSheetIndex, '.xml'))    
    pos <- xmlParse(filename)
    pos <- xmlToList(pos)
    if(is.null(pos$hyperlinks)){
      return(NULL)
    }
    
    pos <- purrr::map_dfr(pos$hyperlinks, as.list)
    pos <- pos[, c('ref', 'id')]
    
    ret <- inner_join(rel, pos, by = 'id')
    ret$tab_idx <- aSheetIndex
    
    return(ret)
  }
  
  EXCEL_TEMP_NAME <- 'unzipped_excel'
  
  tmp_base_dir <- file.path(tempdir(),
                            paste0('tmpexcl', 
                                   as.character(round(runif(1, 1000000000000, 9999999999999)))))
  dir.create(tmp_base_dir)
  on.exit(unlink(tmp_base_dir))
  
  zipfile <- file.path(tmp_base_dir, paste0(EXCEL_TEMP_NAME, '.zip'))
  file.copy(from = aExcelFile, to = zipfile)
  unzip(zipfile, exdir = tmp_base_dir)
  
  ret <- map_df(seq_along(sheets), read_relationships)
  
  ret %>% 
    mutate(tab = sheets[tab_idx]) %>% 
    mutate(ref = paste0("'", tab, "'!", ref)) %>% 
    select(id,tab_idx, tab, ref, target)  ->
    ret

  if(!is.null(aRefOutputFile)){
    write_csv(ret, aRefOutputFile)
  }
  
  return(ret)
}

【讨论】:

  • 代码缺少library(tidyverse) 命令。
  • 我用my own use case 试过这个,map_df 函数返回Error: XML content does not seem to be XML: ''
  • 您的 Excel 文件的版本是什么。该代码适用于 XLSX 格式。
  • 我的文件也是 XLSX。
  • @NotReallyHere12。该错误似乎与 Excel 中的隐藏工作表或临时文件夹有关。我更新了代码。希望它对你有用。
猜你喜欢
  • 2016-08-26
  • 2015-11-20
  • 2020-03-04
  • 2011-08-04
  • 1970-01-01
  • 2022-10-17
  • 1970-01-01
  • 2021-02-01
  • 2015-07-06
相关资源
最近更新 更多