2016-09-25 41 views
-2

我有代碼正在工作,它的webscrapping腳本首先從網頁的URL獲取,然後使用for循環遍歷所有的URL。在循環過程中,它會獲取一些信息並將其保存到數據框中,我首先在循環之前將其創建爲空數據框。這個過程使用rbind並且工作正常。改進我的R代碼 - 建議想要嗎?

但是,我覺得這個代碼不是最優的,可能有一個包,我認爲解決方案將會是可行的......也許不是。但是我希望有人能夠給我一個指示,以更好地編碼這個(如果存在的話)以及它如何實現。

library(rvest) 

URL <- "http://www.transfermarkt.com/premier-league/startseite/wettbewerb/GB1" 

WS <- read_html(URL) 

URLs <- WS %>% html_nodes(".hide-for-pad .vereinprofil_tooltip") %>% html_attr("href") %>% as.character() 
URLs <- paste0("http://www.transfermarkt.com",URLs) 

Catcher1 <- data.frame(Player=character(),P_URL=character()) 

for (i in URLs) { 

    WS1 <- read_html(i) 
    Player <- WS1 %>% html_nodes("#yw1 .spielprofil_tooltip") %>% html_text() %>% as.character() 
    P_URL <- WS1 %>% html_nodes("#yw1 .spielprofil_tooltip") %>% html_attr("href") %>% as.character() 
    temp <- data.frame(Player,P_URL) 
    Catcher1 <- rbind(Catcher1,temp) 
    cat("*") 
} 
+4

我投票關閉這一問題作爲題外話,因爲它應該被移到代碼審查stackexchange – csgillespie

回答

1

你可以嘗試使用purrr代替循環,如下所示:

require(rvest) 
require(purrr) 
require(tibble) 

URLs %>% 
    map(read_html) %>% 
    map(html_nodes, "#yw1 .spielprofil_tooltip") %>% 
    map_df(~tibble(Player = html_text(.), P_URL = html_attr(., "href"))) 

時間:

user system elapsed 
    2.939 2.746 5.699 

是最耗時是通過map(read_html)爬行的步驟。
癱瘓你可以使用例如的plyr平行後端如下:

require(httr) 
doMC::registerDoMC(cores=3) # cores depending on your system 
plyr::llply(URLs, GET, .parallel = TRUE) %>% 
    map(read_html) %>% 
    map(html_nodes, "#yw1 .spielprofil_tooltip") %>% 
    map_df(~tibble(Player = html_text(.), P_URL = html_attr(., "href"))) 

不知何故我Rstudio使用plyr::llply(URLs, read_html, .parallel = TRUE)這就是爲什麼我使用底層httr::GET和在經由map(read_html)下一步驟解析結果墜毀。因此,並行地完成了抓取,但是響應的解析是按順序進行的。

時間:

user system elapsed 
    2.505 0.337 2.940 

在這兩種情況下,結果如下所示:

# A tibble: 1,036 × 2 
      Player        P_URL 
      <chr>        <chr> 
1 David de Gea /david-de-gea/profil/spieler/59377 
2  D. de Gea /david-de-gea/profil/spieler/59377 
3 Sergio Romero /sergio-romero/profil/spieler/30690 
4  S. Romero /sergio-romero/profil/spieler/30690 
5 Sam Johnstone /sam-johnstone/profil/spieler/110864 
6 S. Johnstone /sam-johnstone/profil/spieler/110864 
7 Daley Blind /daley-blind/profil/spieler/12282 
8  D. Blind /daley-blind/profil/spieler/12282 
9 Eric Bailly /eric-bailly/profil/spieler/286384 
10  E. Bailly /eric-bailly/profil/spieler/286384 
# ... with 1,026 more rows 
+0

感謝Floo0,一些出色的想法。如果CSS標識符「#yw1 .spielprofil_tooltip」對於刮取的數據是不同的,那會改變你的選擇嗎? – DenJJ

+0

在您的示例中,所有信息都基於一個CSS標識符。這就是爲什麼它很容易。如果涉及更多的標識符,我很可能會使用一個單獨的函數來接收文檔並返回我想要的數據框。例如。在你的代碼中把'WS1'作爲輸入並返回'temp'。 – Rentrop

0

您的主要問題是您正在增長一個對象。在這種情況下,您正在增長一個數據框。爲了解決這個問題,在之前創建一個大的數據幀並填充它。這是否是瓶頸,很難說。如果length(URLs)很小,那麼它不會有很大的區別。

另一種可能的加速是並行運行循環。也許使用parallel::parSapply。爲了你的循環轉換爲並行版本,只要將「循環」部分的功能,你的代碼將成爲類似:

parallel::parSapply(1:URLs, get_resource) 

或者,您也可以嘗試foreach包。

+0

謝謝,一直在研究foreach並取得一些進展 – DenJJ