2012-01-04 16 views
6

E 'possibile ottenere la data di pubblicazione dei pacchetti CRAN dall'interno di R? Vorrei avere una lista dei k pacchetti CRAN più recentemente pubblicati, o in alternativa tutti i pacchetti pubblicati dopo la data gg-mm-aa. Simile alle informazioni sullo available_packages_by_date.html?available.packages per data di pubblicazione

Il comando available.packages() ha un argomento "fields", ma estrae solo i campi dalla DESCRIZIONE. Il campo data sulla descrizione del pacchetto non è sempre aggiornato.

Posso ottenerlo con una regex intelligente da html page, ma non sono sicuro di quanto sia affidabile e aggiornato questo file html ... A un certo punto Kurt potrebbe decidere di dare al layout un restyling che spezzerebbe la sceneggiatura Un'alternativa è usare timestamp da CRAN FTP ma non sono sicuro di quanto sia buona questa soluzione. Non sono sicuro se ci sia da qualche parte un file formalmente strutturato con date di pubblicazione? Presumo che la pagina HTML sia generata automaticamente da qualche DB.

+2

si può leggere il contenuto della tabella '' html' utilizzando XML :: readHTMLTable'. è questo quello che stavi cercando? – Ramnath

+0

[CRANberries] (http://dirk.eddelbuettel.com/cranberries/index.html) produce un database SQLite con i metadati del pacchetto, incluso quando aggiunto a CRAN, ecc. Sarebbe banale esportarlo e/o CRAN potrebbe semplicemente fare disponibile. Ci sono * alcuni file RData "nascosti" su CRAN, le informazioni potrebbero benissimo esistere ... –

risposta

5

risulta là è un file undocmented "packages.rds" che contiene le date di pubblicazione (non volte) di tutti i pacchetti . Suppongo che questi dati vengano utilizzati per ricreare il file HTML ogni giorno.

Qui di seguito una semplice funzione che estrae date di pubblicazione da questo file:

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

Qui una funzione che utilizza l'HTML e le espressioni regolari. Preferisco comunque ottenere le informazioni da un luogo più formale, anche se l'HTML cambia mai layout.

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

Si potrebbe elaborare la pagina http://cran.r-project.org/src/contrib/, e dividere i campi da spazi bianchi al fine di ottenere il meglio specificato il nome del file di origine del pacchetto, che include la versione # e un suffisso .gz.

Ci sono alcuni altri elementi nell'elenco che non sono file di pacchetto, come i file .rds, varie sottodirectory e così via.

Modificando i cambiamenti nel modo in cui viene presentata la struttura della directory o le posizioni dei file, non riesco a pensare a nulla di più autorevole di questo.

1

Quindi ecco una soluzione che utilizza la directory dir dall'FTP. È un po 'complicato perché l'FTP fornisce la data in formato Linux con un timestamp o un anno. A parte questo, è un lavoro. Non sono ancora convinto che sia comunque affidabile. Se i pacchetti vengono copiati su un altro server, tutti i timestmap potrebbero essere ripristinati.

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 Per fare la codifica non volevo fare.:) – Iterator

3

L'approccio migliore è quello di approfittare del fatto del pacchetto DESCRIPTION viene pubblicato sullo specchio cran, e dal momento che la DESCRIPTION da pacchetto build, contiene informazioni su esattamente quando è stato confezionato:

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"]) 

(che sto limitandola ai primi 20 pacchetti qui per illustrare l'idea di base)

+0

+1 per indicare che la data del pacchetto e l'ultima data di modifica potrebbero essere differenti. – Iterator

+0

Hmz che significa scaricare 3000+ file DESCRIPTION ogni volta che voglio controllare qualcosa di nuovo. Stavo pianificando di eseguirlo come cron job ogni 15 minuti. Non sono sicuro che sia una bella soluzione. – Jeroen

+0

Se si desidera monitorare le modifiche, penso che ci sia un file di livello root che è possibile esaminare. Crantastic fa questo in qualche modo. – hadley

Problemi correlati