2016-09-25 62 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