改进我的R代码 - 需要建议吗?

时间:2016-09-25 10:47:00

标签: r

我的代码正常运行,它是一个网页抓取脚本,首先从网页中获取URL,然后使用for循环运行所有网址。在循环期间,它获取一些信息并将其保存到我首先在循环之前创建为空数据帧的数据帧。该过程使用rbind并且工作正常。

但是,我觉得这段代码并不是最优的,可能有一个包,我认为解决方案是lapply ...也许不是。但我希望有人可以给我一个指向更好的编码方式(如果存在)以及如何实现它的指针。

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("*")
}

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

你的主要问题是你正在成长一个物体。在这种情况下,您正在增长数据框架。要解决这个问题,请在循环之前创建一个大数据框并填入。这是否是瓶颈,很难说清楚。如果length(URLs)很小,那么它就不会产生太大影响。

另一种可能的加速方式是并行运行循环。也许使用parallel::parSapply。要将循环转换为并行版本,只需移动&#34;循环&#34;部分到函数,您的代码将变为:

parallel::parSapply(1:URLs, get_resource)

或者您可以尝试foreach包。