2012-01-04 19 views
6

Có thể lấy ngày xuất bản các gói CRAN từ bên trong R không? Tôi muốn nhận danh sách các gói CRAN được xuất bản gần đây nhất, hoặc tất cả các gói được xuất bản sau ngày dd-mm-yy. Tương tự như thông tin trên available_packages_by_date.html?available.packages theo ngày xuất bản

Lệnh available.packages() có đối số "trường", nhưng điều này chỉ trích xuất các trường từ DESCRIPTION. Trường ngày trên mô tả gói không phải lúc nào cũng cập nhật.

Tôi có thể lấy nó với một regex thông minh từ html page, nhưng tôi không chắc chắn cách đáng tin cậy và cập nhật tệp html này là ... Tại một số điểm Kurt có thể quyết định cung cấp cho bố cục một trang điểm sẽ phá vỡ kịch bản. Một cách khác là sử dụng dấu thời gian từ CRAN FTP nhưng tôi cũng không chắc chắn giải pháp này tốt đến mức nào. Tôi không chắc chắn nếu có một nơi nào đó một tập tin cấu trúc chính thức với ngày xuất bản? Tôi cho rằng trang HTML được tạo tự động từ một số DB.

+2

bạn có thể đọc nội dung của 'bảng html' sử dụng' XML :: readHTMLTable'. Đây có phải là những gì bạn đang tìm kiếm? – Ramnath

+0

[CRANberries] (http://dirk.eddelbuettel.com/cranberries/index.html) tạo ra một cơ sở dữ liệu SQLite với siêu dữ liệu gói, bao gồm cả khi được thêm vào CRAN vv. Nó sẽ là tầm thường để xuất, và/hoặc CRAN chỉ có thể thực hiện nó có sẵn. Có * là * một số tệp RData 'ẩn' trên CRAN, thông tin có thể tồn tại ... –

Trả lời

5

Hóa ra đó là một tập tin undocmented "packages.rds", chứa ngày xuất bản (không phải lần) của tất cả các gói . Tôi cho rằng những dữ liệu này được sử dụng để tạo lại tệp HTML mỗi ngày.

Dưới đây là một chức năng đơn giản mà chiết xuất ngày xuất bản từ tập tin này:

recent.packages.rds <- function(){ 
    mytemp <- tempfile(); 
    download.file("http://cran.r-project.org/web/packages/packages.rds", mytemp); 
    mydata <- as.data.frame(readRDS(mytemp), row.names=NA); 
    mydata$Published <- as.Date(mydata[["Published"]]); 

    #sort and get the fields you like: 
    mydata <- mydata[order(mydata$Published),c("Package", "Version", "Published")]; 
} 
2

Đây là hàm sử dụng HTML và cụm từ thông dụng. Tôi vẫn muốn có được thông tin từ một nơi chính thức hơn mặc dù trong trường hợp HTML thay đổi bố cục.

recent.packages <- function(number=10){ 

    #html is malformed 
    maxlines <- number*2 + 11 
    mytemp <- tempfile() 
    if(getOption("repos") == "@[email protected]"){ 
     repo <- "http://cran.r-project.org" 
    } else { 
     repo <- getOption("repos"); 
    } 
    newurl <- paste(repo,"/web/packages/available_packages_by_date.html", sep=""); 
    download.file(newurl, mytemp); 
    datastring <- readLines(mytemp, n=maxlines)[12:maxlines]; 

    #we only find packages from after 2010-01-01 
    myexpr1 <- '201[0-9]-[0-9]{2}-[0-9]{2} </td> <td> <a href="../../web/packages/[a-zA-Z0-9\\.]{2,}/' 
    myexpr2 <- '^201[0-9]-[0-9]{2}-[0-9]{2}' 
    myexpr3 <- '[a-zA-Z0-9\\.]{2,}/$' 
    newpackages <- unlist(regmatches(datastring, gregexpr(myexpr1, datastring))); 
    newdates <- unlist(regmatches(newpackages, gregexpr(myexpr2, newpackages))); 
    newnames <- unlist(regmatches(newpackages, gregexpr(myexpr3, newpackages))); 

    newdates <- as.Date(newdates); 
    newnames <- substring(newnames, 1, nchar(newnames)-1); 
    returndata <- data.frame(name=newnames, date=newdates); 
    return(head(returndata, number)); 
} 
0

Bạn có thể xử lý các trang http://cran.r-project.org/src/contrib/, và chia các lĩnh vực bởi khoảng trắng để có được tên tập tin nguồn gói quy định đầy đủ, bao gồm các phiên bản # và một hậu tố .gz.

Có một vài mục khác trong danh sách không phải là tệp gói, chẳng hạn như tệp .rds, các thư mục con khác nhau, v.v.

Chặn thay đổi cách cấu trúc thư mục được hiển thị hoặc vị trí của tệp, tôi không thể nghĩ ra bất kỳ điều gì có thẩm quyền hơn điều này.

1

Vì vậy, đây là giải pháp sử dụng danh sách thư mục từ FTP. Đó là một chút khó khăn bởi vì FTP cho ngày ở định dạng linux với một dấu thời gian hoặc một năm. Khác hơn là nó nó là công việc. Tôi vẫn chưa tin chắc điều này là đáng tin cậy. Nếu các gói được sao chép sang máy chủ khác, tất cả các dấu thời gian có thể được đặt lại.

recent.packages.ftp <- function(){ 
    setwd(tempdir()) 
    download.file("ftp://cran.r-project.org/pub/R/src/contrib/", destfile=tempfile(), method="wget", extra="--no-htmlify"); 

    #because of --no-htmlify the destfile argument does not work 
    datastring <- readLines(".listing"); 
    unlink(".listing"); 

    myexpr1 <- "(?<date>[A-Z][a-z]{2} [0-9]{2} [0-9]{2}:[0-9]{2}) (?<name>[a-zA-Z0-9\\.]{2,})_(?<version>[0-9\\.-]*).tar.gz$" 
    matches <- gregexpr(myexpr1, datastring, perl=TRUE); 
    packagelines <- as.logical(sapply(regmatches(datastring, matches), length)); 

    #subset proper lines 
    matches <- matches[packagelines]; 
    datastring <- datastring[packagelines]; 
    N <- length(matches) 

    #from the ?regexpr manual  
    parse.one <- function(res, result) { 
     m <- do.call(rbind, lapply(seq_along(res), function(i) { 
      if(result[i] == -1) return("") 
      st <- attr(result, "capture.start")[i, ] 
      substring(res[i], st, st + attr(result, "capture.length")[i, ] - 1) 
     })) 
     colnames(m) <- attr(result, "capture.names") 
     m 
    } 

    #parse all records 
    mydf <- data.frame(date=rep(NA, N), name=rep(NA, N), version=rep(NA,N)) 
    for(i in 1:N){ 
     mydf[i,] <- parse.one(datastring[i], matches[[i]]); 
    } 
    row.names(mydf) <- NULL; 
    #convert dates 
    mydf$date <- strptime(mydf$date, format="%b %d %H:%M"); 

    #So linux only displays dates for packages of less then six months old. 
    #However strptime will assume the current year for packages that don't have a timestamp 
    #Therefore for dates that are in the future, we subtract a year. We can use some margin for timezones. 
    infuture <- (mydf$date > Sys.time() + 31*24*60*60); 
    mydf$date[infuture] <- mydf$date[infuture] - 365*24*60*60; 

    #sort and return 
    mydf <- mydf[order(mydf$date),]; 
    row.names(mydf) <- NULL; 
    return(mydf); 
} 
+0

+1 Để thực hiện việc viết mã tôi không muốn làm.:) – Iterator

3

Cách tiếp cận tốt nhất là để tận dụng lợi thế của thực tế, gói DESCRIPTION được công bố trên gương cran, và kể từ khi DESCRIPTION là từ việc xây dựng gói, nó chứa các thông tin về chính xác khi nó được đóng gói:

pkgs <- unname(available.packages()[, 1])[1:20] 
desc_urls <- paste("http://cran.r-project.org/web/packages/", pkgs, "/DESCRIPTION", sep = "") 
desc <- lapply(desc_urls, function(x) read.dcf(url(x))) 

sapply(desc, function(x) x[, "Packaged"]) 
sapply(desc, function(x) x[, "Date/Publication"]) 

(tôi đang hạn chế nó đến 20 gói đầu tiên ở đây để minh họa cho ý tưởng cơ bản)

+0

+1 để chỉ ra rằng ngày gói và ngày sửa đổi cuối cùng có thể khác nhau. – Iterator

+0

Hmz có nghĩa là tải xuống 3000+ tệp DESCRIPTION mỗi lần tôi muốn kiểm tra xem có gì mới không. Tôi đã lên kế hoạch để chạy điều này như một công việc cron mỗi 15 phút. Không chắc chắn đó là một giải pháp tốt đẹp. – Jeroen

+0

Nếu bạn chỉ muốn theo dõi các thay đổi, tôi nghĩ rằng có một tập tin cấp độ gốc, bạn có thể kiểm tra. Crantastic làm điều này bằng cách nào đó. – hadley

Các vấn đề liên quan