2015-03-08 8 views
6

ich Schaben http://www.progarchives.com/album.asp?id= und eine Warnmeldung:Scraping .asp Seite mit R

Warning message:
XML content does not seem to be XML:
http://www.progarchives.com/album.asp?id=2
http://www.progarchives.com/album.asp?id=3 http://www.progarchives.com/album.asp?id=4
http://www.progarchives.com/album.asp?id=5

Der Schaber arbeitet für jede Seite getrennt, aber nicht für die Urls b1=2:b2=1000.

library(RCurl) 
library(XML) 

getUrls <- function(b1,b2){ 
    root="http://www.progarchives.com/album.asp?id=" 
    urls <- NULL 
    for (bandid in b1:b2){ 
    urls <- c(urls,(paste(root,bandid,sep=""))) 
    } 
    return(urls) 
} 

prog.arch.scraper <- function(url){ 
SOURCE <- getUrls(b1=2,b2=1000) 
PARSED <- htmlParse(SOURCE) 
album <- xpathSApply(PARSED,"//h1[1]",xmlValue) 
date <- xpathSApply(PARSED,"//strong[1]",xmlValue) 
band <- xpathSApply(PARSED,"//h2[1]",xmlValue) 
return(c(band,album,date)) 
} 

prog.arch.scraper(urls) 

Antwort

6

Hier ist ein alternativer Ansatz mit rvest und dplyr:

library(rvest) 
library(dplyr) 
library(pbapply) 

base_url <- "http://www.progarchives.com/album.asp?id=%s" 

get_album_info <- function(id) { 

    pg <- html(sprintf(base_url, id)) 
    data.frame(album=pg %>% html_nodes(xpath="//h1[1]") %>% html_text(), 
      date=pg %>% html_nodes(xpath="//strong[1]") %>% html_text(), 
      band=pg %>% html_nodes(xpath="//h2[1]") %>% html_text(), 
      stringsAsFactors=FALSE) 

} 

albums <- bind_rows(pblapply(2:10, get_album_info)) 

head(albums) 

## Source: local data frame [6 x 3] 
## 
##      album       date  band 
## 1     FOXTROT Studio Album, released in 1972 Genesis 
## 2    NURSERY CRYME Studio Album, released in 1971 Genesis 
## 3    GENESIS LIVE   Live, released in 1973 Genesis 
## 4  A TRICK OF THE TAIL Studio Album, released in 1976 Genesis 
## 5 FROM GENESIS TO REVELATION Studio Album, released in 1969 Genesis 
## 6   GRATUITOUS FLASH Studio Album, released in 1984 Abel Ganz 

ich nicht bump up fühlte sich die Website mit einer Tonne reqs wie bombardiert so die Sequenz für Ihren Einsatz. pblapply gibt Ihnen einen kostenlosen Fortschrittsbalken.

Um freundlich zu der Website (esp, da es nicht explizit Scraping verbieten) möchten Sie möglicherweise eine Sys.sleep(10) am Ende der get_album_info Funktion werfen.

UPDATE

Server Fehler zu behandeln (in diesem Fall 500, aber es wird für andere zu arbeiten, auch), können Sie try verwenden:

library(rvest) 
library(dplyr) 
library(pbapply) 
library(data.table) 

base_url <- "http://www.progarchives.com/album.asp?id=%s" 

get_album_info <- function(id) { 

    pg <- try(html(sprintf(base_url, id)), silent=TRUE) 

    if (inherits(pg, "try-error")) { 
    data.frame(album=character(0), date=character(0), band=character(0)) 
    } else { 
    data.frame(album=pg %>% html_nodes(xpath="//h1[1]") %>% html_text(), 
       date=pg %>% html_nodes(xpath="//strong[1]") %>% html_text(), 
       band=pg %>% html_nodes(xpath="//h2[1]") %>% html_text(), 
       stringsAsFactors=FALSE) 
    } 

} 

albums <- rbindlist(pblapply(c(9:10, 23, 28, 29, 30), get_album_info)) 

##      album       date   band 
## 1: THE DANGERS OF STRANGERS Studio Album, released in 1988 Abel Ganz 
## 2: THE DEAFENING SILENCE Studio Album, released in 1994 Abel Ganz 
## 3:    AD INFINITUM Studio Album, released in 1998 Ad Infinitum 

Sie jede nicht bekommen Einträge für die fehlerhaften Seiten (in diesem Fall gibt es nur die Einträge von ID 9, 10 und 30 zurück).

+0

Vielen Dank! Es funktionierte, außer ich bekomme eine Fehlermeldung, die besagt, dass es keine Funktion '" bind_rows "' gibt. Ich habe alle Pakete neu installiert, aber immer noch kein Glück. – torentino

+0

'rbindlist' hat den Trick gemacht. Ich wollte schon seit einiger Zeit in 'Rvest' gehen, also hat mich dein Code dazu veranlasst, mich genauer damit zu beschäftigen. Danke @hrbrmstr. Eine weitere Frage: Was macht 'sprintf' eigentlich in der html-Funktion? – torentino

+0

Es gibt ungefähr 48.000 Seiten, an denen ich interessiert bin zu scrapen, aber ich bemerkte, dass der Scraper aufhört, wenn er auf defekte Seiten stößt, d. H. "Interner Fehler". Eine Möglichkeit, mit ihnen umzugehen, besteht darin, auf jeder Seite eine Notiz zu prüfen, welche gebrochen sind und die guten innerhalb des 'Alben'-Objekts zu verketten, aber das ist zeitaufwendig. Haben Sie Vorschläge zum Umgang mit kaputten Seiten? Prost. – torentino

4

Anstelle von xpathApply() können Sie den ersten Knoten in den Knotensets jedes Pfades unterteilen und xmlValue() darauf aufrufen. Hier ist, was ich kam mit,

library(XML) 
library(RCurl) 

## define the urls and xpath queries 
urls <- sprintf("http://www.progarchives.com/album.asp?id=%s", 2:10) 
path <- c(album = "//h1", date = "//strong", band = "//h2") 

## define a re-usable curl handle for the c-level nodes 
curl <- getCurlHandle() 
## allocate the result list 
out <- vector("list", length(urls)) 

## do the work  
for(u in urls) { 
    content <- getURL(u, curl = curl) 
    doc <- htmlParse(content, useInternalNodes = TRUE) 
    out[[u]] <- lapply(path, function(x) xmlValue(doc[x][[1]])) 
    free(doc) 
} 

## structure the result 
data.table::rbindlist(out) 
#       album       date  band 
# 1:     FOXTROT Studio Album, released in 1972 Genesis 
# 2:    NURSERY CRYME Studio Album, released in 1971 Genesis 
# 3:    GENESIS LIVE   Live, released in 1973 Genesis 
# 4:  A TRICK OF THE TAIL Studio Album, released in 1976 Genesis 
# 5: FROM GENESIS TO REVELATION Studio Album, released in 1969 Genesis 
# 6:   GRATUITOUS FLASH Studio Album, released in 1984 Abel Ganz 
# 7:   GULLIBLES TRAVELS Studio Album, released in 1985 Abel Ganz 
# 8: THE DANGERS OF STRANGERS Studio Album, released in 1988 Abel Ganz 
# 9:  THE DEAFENING SILENCE Studio Album, released in 1994 Abel Ganz 

Update: So behandeln die id Abfragen nicht existieren, können wir einen Zustand mit RCurl::url.exists() schreiben, die die schlechten Griffe. Daher gibt die folgende Funktion getAlbums() je nach dem Status der URL einen Zeichenvektor der abgerufenen XML-Werte oder NA zurück. Das kannst du natürlich ändern, wenn du willst. Das war nur eine Methode, die mir in den frühen Morgenstunden in den Sinn kam.

getAlbums <- function(url, id = numeric(), xPath = list()) { 
    urls <- sprintf("%s?id=%d", url, id) 
    curl <- getCurlHandle() 
    out <- vector("list", length(urls)) 
    for(u in urls) { 
     out[[u]] <- if(url.exists(u)) { 
      content <- getURL(u, curl = curl) 
      doc <- htmlParse(content, useInternalNodes = TRUE) 
      lapply(path, function(x) xmlValue(doc[x][[1]])) 
     } else { 
      warning(sprintf("returning 'NA' for urls[%d] ", id[urls == u])) 
      structure(as.list(path[NA]), names = names(path)) 
     } 
     if(exists("doc")) free(doc) 
    } 
    data.table::rbindlist(out) 
} 

url <- "http://www.progarchives.com/album.asp" 
id <- c(9:10, 23, 28, 29, 30) 
path <- c(album = "//h1", date = "//strong", band = "//h2") 
getAlbums(url, id, path) 
#      album       date   band 
# 1: THE DANGERS OF STRANGERS Studio Album, released in 1988 Abel Ganz 
# 2: THE DEAFENING SILENCE Studio Album, released in 1994 Abel Ganz 
# 3:      NA        NA   NA 
# 4:      NA        NA   NA 
# 5:      NA        NA   NA 
# 6:    AD INFINITUM Studio Album, released in 1998 Ad Infinitum 
# 
# Warning messages: 
# 1: In albums(url, id, path) : returning 'NA' for urls[23] 
# 2: In albums(url, id, path) : returning 'NA' for urls[28] 
# 3: In albums(url, id, path) : returning 'NA' for urls[29] 
+0

@ Richard Scriven. Vielen Dank! Das funktioniert gut, außer dass ich mit den defekten Links auf das gleiche Problem wie oben gestoßen bin. – torentino

+0

Funktioniert! Danke für die Aktualisierung und Fehlerbehandlung. – torentino