2016-08-06 22 views
3

Die Tabelle, die mich interessiert, ist die Wikipedia-Tabelle von Michelin-Sterne-Restaurants in NYC, und die Anzahl der Sterne ausgezeichnet wird durch Bilder angezeigt.Scraping Wikipedia HTML-Tabelle mit Bildern, Text und leere Zellen mit R

Screenshot of wikipedia table

konnte ich die Tabelle mit zwei Schritten kratzen (zuerst die Worte in dem „Namen“ und „Borough“ Spalten erhalten, zweite die Alt-Tags in der Tabelle Körper bekommen), aber ich mag wissen, ob es in einem Schritt gemacht werden kann. Ich war in der Lage, die Daten mit dem Rettungspaket zu kratzen.

Da Wikipedia-Seiten nicht von der XML :: readHTMLTable-Funktion gelesen werden können, habe ich das hmttab-Paket ohne Glück versucht, weil ich die Funktion für das bodyFun-Argument nicht herausfinden konnte. Um ehrlich zu sein, ich bin ein Neuling für Web Scraping ... und funktioniert.

Fragen, die ich als Referenz genannt:

Scraping html table with images using XML R package

Scraping html tables into R data frames using the XML package

Hier ist mein Code:

library(stringr) 
library(rvest) 
library(data.table) 

url <- "http://en.wikipedia.org/wiki/List_of_Michelin_starred_restaurants_in_New_York_City" 

#Scrape the first two columns, restaurant name and borough 
name.boro <- url %>% read_html() %>% html_nodes("table") %>% html_table(fill = TRUE) 
name.boro <- as.data.table(name.boro[[1]]) 
name.boro[, 3:length(name.boro) := NULL] 
135 * 13 #1,755 cells in first table 

#scrape tables for img alt 
#note that because I used the "td" node, entries for all cells in all tables were pulled 
stars <- url %>% read_html() %>% html_nodes("td") %>% html_node("img") %>% html_attr("alt") 
stars 

#Make vector of numbers to index each column 
df <- vector("list", 13) 
for (i in 1:13){ 
    df[[i]] <- seq(i, 1755, 13) 
} 

#Put everything together 
Mich.Guide <- name.boro 
Mich.Guide[, c("X2006", "X2007", "X2008", "X2009", "X2010", "X2011", "X2012", "X2013", "X2014", "X2015", 
       "X2016") := .(stars[unlist(df[3])], stars[unlist(df[4])], stars[unlist(df[5])], 
          stars[unlist(df[6])], stars[unlist(df[7])], stars[unlist(df[8])], 
          stars[unlist(df[9])], stars[unlist(df[10])], stars[unlist(df[11])], 
          stars[unlist(df[12])], stars[unlist(df[13])])] 

Thank you!

+0

_ "Da Wikipedia-Seiten nicht mit dem XML-Paket gelesen werden können ..." _ => bitte erklären Sie diese Miss-Wahrheit. – hrbrmstr

+0

Folgendes warf einen Fehler: 'URL <-" http://en.wikipedia.org/wiki/List_of_Michelin_starred_restaurants_in_New_York_City "' 'ReadHTMLTable (URL, die = 1)' ... so habe ich es hier [http: //stackoverflow.com/questions/7407735/importing-wikipedia-tables-in-r](http://stackoverflow.com/questions/7407735/importing-wikipedia-tables-in-r) und Benutzer Shambho kommentiert, dass die Sicherheit Verbindung funktioniert nicht im Paket. Können Sie den Befehl readHTMLTable auf dieser Site verwenden? – MiamiCG

+0

Sagen 'readHTMLTable()' funktioniert nicht == "kann das XML-Paket nicht verwenden" ist ein wenig unaufrichtig – hrbrmstr

Antwort

2

können Sie die

require(rvest) 
url <- "http://en.wikipedia.org/wiki/List_of_Michelin_starred_restaurants_in_New_York_City" 
doc <- read_html(url) 
col_names <- doc %>% html_nodes("#mw-content-text > table > tr:nth-child(1) > th") %>% html_text() 
tbody <- doc %>% html_nodes("#mw-content-text > table > tr:not(:first-child)") 

extract_tr <- function(tr){ 
    scope <- tr %>% html_children() 
    c(scope[1:2] %>% html_text(), 
    scope[3:length(scope)] %>% html_node("img") %>% html_attr("alt")) 
} 

res <- tbody %>% sapply(extract_tr) 
res <- as.data.frame(t(res), stringsAsFactors = FALSE) 
colnames(res) <- col_names 

nun folgenden versuchen Sie die raw-Tisch. Ich verlasse das Parsing der Spalten in Integer und die Spaltennamen zu Ihnen

+0

Danke - ich denke, diese Lösung ist universeller. Ich hoffe eines Tages würde ein Paket eine kürzere Lösung in einer Funktion verpackt haben! – MiamiCG

1

etwas anderen Ansatz:

library(rvest) 
library(purrr) 
library(stringi) 

pg <- read_html("http://en.wikipedia.org/wiki/List_of_Michelin_starred_restaurants_in_New_York_City") 
html_nodes(pg, xpath=".//table[contains(@class, 'wikitable')]/tr[not(th)]") %>% 
    map_df(function(x) { 
    r_name <- html_text(html_nodes(x, xpath=".//td[1]")) 
    borough <- html_text(html_nodes(x, xpath=".//td[2]")) 
    map(3:13, function(y) { 
     stars <- html_attr(html_nodes(x, xpath=sprintf(".//td[%d]/a", y)), "href") 
     if (length(stars)==0) { 
     NA 
     } else { 
     stri_match_first_regex(stars, "Michelin-([[:digit:]])")[,2] 
     } 
    }) -> refs 
    refs <- setNames(refs, c(2006:2016)) 
    as.data.frame(c(r_name=r_name, borough=borough, refs), stringsAsFactors=FALSE) 
    }) -> michelin_nyc 

dplyr::glimpse(michelin_nyc) 

## Observations: 135 
## Variables: 13 
## $ r_name <chr> "Adour", "Ai Fiori", "Alain Ducasse at the... 
## $ borough <chr> "Manhattan", "Manhattan", "Manhattan", "Ma... 
## $ X2006 <chr> NA, NA, "3", NA, NA, NA, NA, "1", NA, NA, ... 
## $ X2007 <chr> NA, NA, NA, NA, NA, NA, NA, "1", NA, NA, N... 
## $ X2008 <chr> NA, NA, NA, NA, NA, NA, NA, "1", "1", NA, ... 
## $ X2009 <chr> "2", NA, NA, NA, "1", "1", NA, "1", "1", N... 
## $ X2010 <chr> "1", NA, NA, NA, NA, "2", NA, "1", "1", NA... 
## $ X2011 <chr> "1", NA, NA, "1", NA, "2", NA, "1", "1", N... 
## $ X2012 <chr> "1", "1", NA, "1", NA, NA, NA, "1", NA, NA... 
## $ X2013 <chr> "1", "1", NA, "1", NA, NA, NA, "1", NA, "1... 
## $ X2014 <chr> NA, "1", NA, "1", NA, NA, NA, "1", NA, "1"... 
## $ X2015 <chr> NA, "1", NA, "1", NA, NA, "1", NA, NA, "2"... 
## $ X2016 <chr> NA, "1", NA, "1", NA, NA, "1", NA, NA, "2"... 

die auch total ist machbar mit dem XML Paket, wie Sie unten sehen können:

library(XML) 
library(RCurl) 
library(stringi) 

pg <- getURL("https://en.wikipedia.org/wiki/List_of_Michelin_starred_restaurants_in_New_York_City") 
pg <- htmlParse(pg) 
rows <- getNodeSet(pg, "//table[contains(@class, 'wikitable')]/tr[not(th)]") 
do.call(rbind, lapply(rows, function(x) { 
    r_name <- xpathSApply(x, ".//td[1]", xmlValue) 
    borough <- xpathSApply(x, ".//td[2]", xmlValue) 
    lapply(3:13, function(y) { 
    stars <- xpathSApply(x, sprintf(".//td[%d]/a", y), xmlGetAttr, "href") 
    if (length(stars)==0) { 
     NA 
    } else { 
     stri_match_first_regex(stars, "Michelin-([[:digit:]])")[,2] 
    } 
    }) -> refs 
    refs <- setNames(refs, c(2006:2016)) 
    as.data.frame(c(r_name=r_name, borough=borough, refs), stringsAsFactors=FALSE) 
})) -> michelin_nyc 

str(michelin_nyc) 

## 'data.frame': 135 obs. of 13 variables: 
## $ r_name : chr "Adour" "Ai Fiori" "Alain Ducasse at the Essex House" "Aldea" ... 
## $ borough: chr "Manhattan" "Manhattan" "Manhattan" "Manhattan" ... 
## $ X2006 : chr NA NA "3" NA ... 
## $ X2007 : chr NA NA NA NA ... 
## $ X2008 : chr NA NA NA NA ... 
## $ X2009 : chr "2" NA NA NA ... 
## $ X2010 : chr "1" NA NA NA ... 
## $ X2011 : chr "1" NA NA "1" ... 
## $ X2012 : chr "1" "1" NA "1" ... 
## $ X2013 : chr "1" "1" NA "1" ... 
## $ X2014 : chr NA "1" NA "1" ... 
## $ X2015 : chr NA "1" NA "1" ... 
## $ X2016 : chr NA "1" NA "1" ... 
+0

Vielen Dank, dass Sie es in RVest und XML gemacht haben! Die Ausgabe ist sehr sauber. – MiamiCG