使用 rvest 下载需要从网站登录的压缩文件 (morphosource) HTML

Downloading a zipped file requiring login from a website (morphosource) HTML using rvest

我知道Whosebug上也有类似的问题,但是翻了翻还是没有找到下载我需要的文件的方法。我有一个 http 网址列表。当我登录到感兴趣的网站 (MorphoSource) 并在浏览器中输入地址时,它会自动下载一个压缩文件夹。我需要从 R 中执行此操作,以便我可以循环下载其中的许多文件夹。

这是一个这样的 http 地址(尽管没有登录就不会发生任何事情):"http://www.morphosource.org/index.php/Detail/MediaDetail/DownloadMedia/media_id/119/media_file_id/52"

我已经使用下面的代码取得了最大的进步,但我仍然收到一条错误消息,提示我 Submitting with 'NULL' 并且当我查看下载的文件时,它大约为 8kb,而它应该超过 50,000kb

  library(rvest) 
    login<-"https://www.morphosource.org/LoginReg/form"
    pgsession<-html_session(login)
    pgform<-html_form(pgsession)[[2]]  
    filled_form<-set_values(pgform, username="TestingPackage@gmail.com", password="testingpackage")
    submit_form(pgsession, filled_form)
download.file("http://www.morphosource.org/index.php/Detail/MediaDetail/DownloadMedia/media_id/119/media_file_id/52", "testfile")

我是 R 的新手,对通过 R 中的网址下载压缩文件夹的想法完全陌生,因此非常感谢您的帮助。

我们只需要为您做一些会话管理:

morphosource_dl <- function(media_id, # if end of URL is /media_id/119/media_file_id/52 then this is 119
                            media_file_id, # if end of URL is /media_id/119/media_file_id/52 then this is 52
                            overwrite = TRUE, # overwrite file if it already exists?
                            .progress = TRUE, # show a download progress bar?
                            username = Sys.getenv("MORPHOSOURCE_EMAIL"), # pass in here or store in ~/.Renviron
                            password = Sys.getenv("MORPHOSOURCE_PASSWORD")) { # pass in here or store in ~/.Renviron

  suppressPackageStartupMessages({
    library(httr, warn.conflicts = FALSE, quietly = TRUE, verbose = FALSE)
    library(rvest, warn.conflicts = FALSE, quietly = TRUE, verbose = FALSE)
  }) 

  # Start a sessiion
  res <- httr::GET(url = "https://www.morphosource.org/Splash/Index")

  # login
  httr::POST(
    url = "https://www.morphosource.org/LoginReg/login",
    httr::add_headers(
      Referer = "https://www.morphosource.org/LoginReg/form"
    ),
    body = list(
      username = username, 
      password = password
    ),
    encode = "form"
  ) -> res

  # if successful
  if (length(html_nodes(httr:::content(res), xpath=".//*[contains(., 'You have been logged in')]")) > 0) {

    httr::stop_for_status(res) # make sure it really was successful

    # do this to get filename
    httr::HEAD(
      url = sprintf(
        "https://www.morphosource.org/index.php/Detail/MediaDetail/DownloadMedia/media_id/%s/media_file_id/%s",
        media_id, media_file_id
      )
    ) -> res

    fil <- gsub("^.*filename=", "", res$headers["content-disposition"])

    httr::GET(
      url = "https://www.morphosource.org/index.php/Detail/MediaDetail/DownloadMedia/media_id/119/media_file_id/52",
      httr::write_disk(fil, overwrite = overwrite),
      if (.progress) httr::progress()
    ) -> res

    if (.progress) cat("\n")

    return(fil)

  } else {
    message("Error logging in")
    httr::stop_for_status(res)
  }

}

你的 URL 是 http://www.morphosource.org/index.php/Detail/MediaDetail/DownloadMedia/media_id/119/media_file_id/52(实际上是 https://www.morphosource.org/index.php/Detail/MediaDetail/DownloadMedia/media_id/119/media_file_id/52,这是一个重要的区别)。

这意味着 "media id" 是 119 而 "media file id" 是 52

如果您做对了并在您的 ~/.Renviron 中输入:

MORPHOSOURCE_EMAIL=me@example.com
MORPHOSOURCE_PASSWORD=aBetterP@s$w0rDThanThis

并刷新你的 R 会话,然后你可以这样做:

morphosource_dl("119", "52")
## Downloading: ... MB
## [1] "Morphosource_AMNH-M-100635_M119-52.zip"

将为您下载。

否则你可以这样做:

morphosource_dl(
  media_id = "119", 
  media_file_id = "52", 
  username = "donotdothis@example.com",
  password = "embeddingCredentialsInScriptsIsNotTooBright"
)

它仍然会下载它。

在这两种情况下,它都是 returns 文件的名称。

您可以使用 overwrite 参数控制是否覆盖文件(默认为 TRUE),是否需要进度条(默认为 TRUE)使用 .progress.

您遇到的问题是 download.file()rvest 的基础一无所知,即 curlhttr(以及 xml2)。因此 download.file() 无法获取您的 rvest 调用生成的会话 cookie。您可能只是调用了 httr::GET() 和下载 link 的 https 版本,并在您开始使用后在其中使用 httr::write_disk(),但是上面的函数封装了这一切都变成了一个动作,并且还找出了文件名(你必须手动设置)之前。

我们只是做了 "long way" 并模仿了浏览器对 GETPOST 所做的: