0

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

该列表(该列表是一个名为 data.frame的 100 行和一个名为并且采用字符格式my_list的单列)看起来像这样: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文件中?

4

3 回答 3

2

请注意,这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"
    )
  )

由于 url 已经在 a 中,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/以了解更多信息。

于 2021-04-09T19:51:52.447 回答
1

您的数据中似乎有某些 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) {})
})
于 2021-04-10T08:14:42.243 回答
1

因此,假设您有一个包含您的 pdf 位置 URL 的列的data.frame调用。my_df根据您的评论,似乎某些 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, file = paste0("article_", id, ".rds"))
    "OK"
    
  }, error = function(e) {return("FAILED")})
}

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

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

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

于 2021-04-09T19:37:59.243 回答