微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为“加载”和“保存”进程创建一个循环

如何解决为“加载”和“保存”进程创建一个循环

我有一个包含 url 链接列表的 data.frame (dim: 100 x 1),每个 url 看起来像这样:https:blah-blah-blah.com/item/123/index.do .

列表(列表是一个名为 my_list 的数据框,有 100 行和一个名为 col 的单列,采用字符格式 $ col: chr)一起看起来像这样:>

 1 "https:blah-blah-blah.com/item/123/index.do"
 2" https:blah-blah-blah.com/item/124/index.do"
 3 "https:blah-blah-blah.com/item/125/index.do"

etc.

我正在尝试将这些 url 中的每一个导入 R 并将对象共同保存为与文本挖掘程序兼容的对象。

我知道如何手动成功转换这些网址(在列表中):

library(pdftools)
library(tidytext)
library(textrank)
library(dplyr)
library(tm)

#1st document
url <- "https:blah-blah-blah.com/item/123/index.do"

article <- pdf_text(url)

一旦成功创建了这个“文章文件,我就可以检查它:

str(article)

chr [1:13] 

看起来像这样:

[1] "abc ....."

[2] "def ..."

etc etc

[15] "ghi ...:

从这里,我可以成功地将其保存为 RDS 文件

saveRDS(article,file = "article_1.rds")

有没有办法同时对所有 100 篇文章执行此操作?也许有一个循环?

类似:

for (i in 1:100) {

url_i <- my_list[i,1]

article_i <- pdf_text(url_i)

saveRDS(article_i,file = "article_i.rds")

}

如果写得正确,它会将每篇文章保存为 RDS 文件(例如 article_1.rds、article_2.rds、... article_100.rds)。

那么是否可以将所有这些文章保存到一个 rds 文件中?

解决方法

请注意,list 不是一个对象的好名字,因为这会 暂时覆盖 list() 函数。我认为这通常很好 根据变量的内容命名变量。也许 url_df 会是 好名字。

library(pdftools)
#> Using poppler version 20.09.0
library(tidyverse)

url_df <-
  data.frame(
    url = c(
      "https://www.nimh.nih.gov/health/publications/autism-spectrum-disorder/19-mh-8084-autismspecdisordr_152236.pdf","https://www.nimh.nih.gov/health/publications/my-mental-health-do-i-need-help/20-mh-8134-mymentalhealth-508_161032.pdf"
    )
  )

由于网址已经在 data.frame 中,我们可以将文本数据存储在 一个额外的专栏。这样数据就可以很容易地供以后使用 步骤。

text_df <- 
  url_df %>% 
  mutate(text = map(url,pdf_text))

我们现在可以存储所有数据,而不是将每个文本保存在单独的文件中 在单个文件中:

saveRDS(text_df,"text_df.rds")

由于历史原因,for 循环在 R 社区中并不是很流行。 base R 具有 *apply() 函数族,它提供了一个函数式 迭代的方法。 tidyverse 有 purrr 包和 map*() 改进 *apply() 函数的函数。

我建议看一看 https://purrr.tidyverse.org/ 了解详情。

,

假设您有一个名为 data.framemy_df,其中有一列包含您的 pdf 位置的 URL。根据您的评论,似乎某些 URL 会导致 PDF 损坏。在这些情况下,您可以使用 tryCatch 报告哪些链接已损坏并手动检查这些链接有什么问题。

您可以像这样在 for 循环中执行此操作:

my_df <- data.frame(url = c(
  "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",# working pdf
  "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pfd" # broken pdf
))

# make some useful new columns
my_df$id <- seq_along(my_df$url)
my_df$status <- NA

for (i in my_df$id) {
  
  my_df$status[i] <- tryCatch({
    
    message("downloading ",i) # put a status message on screen
    article_i <- suppressMessages(pdftools::pdf_text(my_df$url[i]))
    saveRDS(article_i,file = paste0("article_",i,".rds"))
    "OK"
    
  },error = function(e) {return("FAILED")}) # return the string FAILED if something goes wrong
  
}
my_df$status
#> [1] "OK"     "FAILED"

我特意在示例数据中加入了一个断开的链接,以展示它的外观。

或者,您可以使用 apply 系列中的循环。不同之处在于,*apply 不是遍历向量并应用相同的代码直到向量结束,而是采用一个函数,将其应用于列表的每个元素(或可以转换为列表的对象)并返回结果从一次迭代开始。许多人一开始发现 *apply 函数很混乱,因为通常人们在一行中定义和应用函数。让我们让函数更明确:

s_download_pdf <- function(link,id) {
  tryCatch({
    message("downloading ",id) # put a status message on screen
    article_i <- suppressMessages(pdftools::pdf_text(link))
    saveRDS(article_i,id,error = function(e) {return("FAILED")})
}

既然我们有了这个功能,让我们用它来下载所有文件。我正在使用 mapply,它一次遍历两个向量,在本例中为 idurl 列:

my_df$status <- mapply(s_download_pdf,link = my_df$url,id = my_df$id)
my_df$status
#> [1] "OK"     "FAILED"

我认为您选择哪种方法没有太大区别,因为速度将受到您的互联网连接而不是 R 的瓶颈。只是想你可能会喜欢这种比较。

,

您的数据中似乎有某些 url 不是有效的 pdf 文件。您可以将其包装在 tryCatch 中以处理错误。如果您的数据框名为 df,其中包含 url 列,您可以执行以下操作:

library(pdftools)

lapply(seq_along(df$url),function(x) {
  tryCatch({
    saveRDS(pdf_text(df$url[x]),file = sprintf('article_%d.rds',x)),},error = function(e) {})
})

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。