【问题标题】:Loop through url's with R使用 R 循环遍历 url
【发布时间】:2018-07-07 16:08:53
【问题描述】:

我需要从 URL 下载一系列 Excel 文件,所有文件如下:

http://example.com/orResultsED.cfm?MODE=exED&ED=01&EventId=31
http://example.com/orResultsED.cfm?MODE=exED&ED=02&EventId=31
...
http://example.com/orResultsED.cfm?MODE=exED&ED=87&EventId=31

 

我在循环中有一些构建块,例如:

for(i in 1:87) {
    url <- paste0("http://example.com/orResultsED.cfm?MODE=exED&ED=", i, "&EventId=31")
    file <- paste0("Data/myExcel_", i, ".xlsx")
    if (!file.exists(file)) download.file(url, file) 
}

 

我的问题

  1. 我需要 seq 来添加 0(我试过 sprintf 没有运气)
  2. 我还想导入 Excel 文件,跳过前两行并将它们附加到另一行之后(它们也有相同的列)

 

更新

@akrun 解决方案效果很好。但事实证明,并非我所有的 Excel 文件都有相同的列数:

map(files, ~read.xlsx(.x, 
                         colNames = FALSE,
                         sheet = 1, 
                         startRow = 4,
                         )) %>%
  bind_rows

Error in bind_rows_(x, .id) : 
  Column `X1` can't be converted from numeric to character

我认为这个错误实际上指向了不相等的列数。我尝试添加fill = NA(在测试map_df()时),但没有帮助。

【问题讨论】:

  • FWIW,只要你不是想赚钱,“艾伯塔省选举”实际上会特意告诉你,他们允许个人和教育抓取。请尽量友善并添加Sys.sleep(5) tho。没有必要比这更快地下载文件。还有一个真的很好的机会,一封电子邮件最终可能会给你一个 ZIP 文件,甚至是一组 SQL 来加载这些文件而无需抓取。但是,嘿,试试example.com
  • 谢谢!我对网络抓取很陌生。我不知道有人可以要求 SQL 访问。 example.com 更多的是缩短链接并使其适合 SO 中的一行!
  • 哦,我从你的核动画示例中学到了if (!file.exists(file)) download.file(url, file)!感谢您的参与!

标签: r loops web-scraping rvest


【解决方案1】:

我们可以用sprintf创建它

paste0("http://example.com/orResultsED.cfm?MODE=exED&ED=", sprintf("%02d", 1), "&EventId=31")
#[1] "http://example.com/orResultsED.cfm?MODE=exED&ED=01&EventId=31"

在循环中,

for(i in 1:87) {
  i1 <- sprintf('%02d', i)
   url <- paste0("http://example.com/orResultsED.cfm?MODE=exED&ED=", i1, "&EventId=31")
   file <- paste0("Data/myExcel_", i, ".xlsx")
   if (!file.exists(file)) download.file(url, file) 
}

假设文件下载到工作目录

files <- list.files(full.names = TRUE)
library(openxlsx)
library(purrr)
library(dplyr)
map(files, ~read.xlsx(.x, sheet = 1, startRow = 3))  %>%
      bind_rows

或者如 cmets 中提到的@hrbrmstr,可以使用map_df,它返回单个数据集

map_df(files, ~read.xlsx(.x, sheet = 1, startRow = 3))

更新

根据 OP 的 cmets,某些数据集的列类似乎有所不同。在这种情况下,bind_rows 会给出错误。一种选择是使用来自data.tablerbindlist

map(files, ~read.xlsx(.x, sheet = 1, startRow = 3))  %>%
      data.table::rbindlist(fill = TRUE)

【讨论】:

  • 如果您已经在使用purrr,为什么不使用map_df? (严重的问题……好奇你是否注意到性能问题或奇怪的行为/等等)。
  • @hrbrmstr 我想过这个问题。但是,如果列数不相等,它可能会中断,那么bind_rows 可以选择fill
  • 人力资源管理。 map_df() 也一直为我填满,但我也尝试仅将它与 list 输出一起使用(它明显比数据帧快,尤其是如果返回很多小的数据帧)
  • 谢谢!这几乎可以工作。请参阅更新发布...是的,我有不相等的不。上校。
  • @ThomasSpeidel 我认为这是list 元素之一中列类差异的问题。例如df1 &lt;- data.frame(A = 1:5, B = as.character(6:10), stringsAsFactors = FALSE); df2 &lt;- data.frame(A = 7:12, B = 8:13) bind_rows(df1, df2)# Error in bind_rows_(x, .id) 您可以使用来自data.tablerbindlist 即。 rbindlist(list(df1, df2), fill = TRUE)B 无法从字符转换为整数
【解决方案2】:

在 1 个循环中下载和阅读。如果不使用 plyr::rbind.fill 而不是 do.call(rbind, list) 之类的东西,希望这些列是对齐的

do.call(rbind, lapply(1:87, function(n) {
    url <- paste0("http://example.com/orResultsED.cfm?MODE=exED&ED=", 
        sprintf("%02d", n), "&EventId=31")
    file <- paste0("Data/myExcel_", n, ".xlsx")
    if (!file.exists(file)) download.file(url, file) 
    readxl::read_excel(file, skip=2)
    Sys.sleep(5)
}))

【讨论】:

    【解决方案3】:

    你也可以使用regmatches

     num=sprintf("%02.0f",1:87)
     urls=rep("http://example.com/orResultsED.cfm?MODE=exED&ED=01&EventId=31",87)
    `regmatches`(urls,regexpr("\\d+",urls))<-num
     urls[87]
    [1] "http://example.com/orResultsED.cfm?MODE=exED&ED=87&EventId=31"
    

    拥有所有文件:

     files <- paste0("Data/myExcel_",num , ".xlsx")
    

    下载文件:

      mapply(function(x,y)if(!file.exists(x))download.file(y,x),files,urls)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-08-27
      • 1970-01-01
      • 1970-01-01
      • 2010-12-09
      • 2016-06-28
      • 1970-01-01
      相关资源
      最近更新 更多