2016-01-06 120 views
0

我想解析一些使用Rcurl和XML包的網站。 根據任務管理器rsession進程執行〜1個執行後使用12G。 致電R中的內存泄漏?

rm(list = ls()) 
gc() 

我所有的記憶仍然被rsession使用。問題是什麼? 下面是代碼:

library(XML); 
    library(RCurl); 
    rm(list = ls()) 
    if (file.exists('cookies.txt')){ 
     file.remove('cookies.txt') 
    } 
    if (file.exists('words.txt')){ 
     file.remove('words.txt') 
    } 

    doGet <- function(url, encode = 'windows-1251') { 
     html <- tryCatch(
       { 
        getURL(url, curl=curl, .encoding = encode) 
       }, warning = function(w) { 
        print(paste('warning: ', url, w)) 
       }, error = function(e) { 
        print(paste('error: ', url, e)) 
       }, finally = {} 
     ) 
     write(x = html, file = '~tmp.html', append = F) 
     htmlTreeParse(file = '~tmp.html', useInternalNodes = T, encoding = encode) 
    } 

    makeURL <- function(url) { 
     paste(url_base, url, sep = "") 
    } 

    parse.morph <- function(n){ 
     val <- xmlValue(n, encoding = 'UTF-8') 
     res <- tolower(gsub(" |-", "", strsplit(val, ':')[[1]][[2]])) 
     rm(val) 
     res 
    } 

    morphToList <- function(morphs) { 
     print(paste(morphs, collapse='')) 
     res <- list() 
     res$prefix = unlist(strsplit(morphs[1], split = ';')) 
     res$base = unlist(strsplit(morphs[2], split = ';')) 
     res$suffix = unlist(strsplit(morphs[3], split = ';')) 
     res$ending = unlist(strsplit(morphs[4], split = ';')) 
     res 
    } 

    indexOf <- function(val, str) { 
     grep(val, strsplit(str, "")[[1]]) 
    } 

    parse.word <- function(page) { 
     xpathSApply(page, "//div[@class='word-article']/ul/li", parse.morph) 
    } 

    append <- function(df, m) { 
     tmp <- data.frame(p1 = m$prefix[3], p2 = m$prefix[2], p3 = m$prefix[1], 
          b1 = m$base[1], b2 = m$base[2], 
          s1 = m$suffix[1], s2 = m$suffix[2], s3 = m$suffix[3], s4 = m$suffix[4], 
          e1 = m$ending[1], e2 = m$ending[2], e3 = m$ending[3]) 
     rbind(df, tmp) 
    } 

    parsePage <- function(page) { 
     words.url <- xpathSApply(page, "//tr[contains(@class, 'row')]/td/a", xmlGetAttr, 'href') 
     df <- data.frame(p1 = c(), p2 = c(), p3 = c(), b1 = c(), b2 = c(), s1 = c(), s2 = c(), s3 = c(), s4 = c(), e1 = c(), e2 = c(), e3 = c()) 
     for(word.url in words.url) { 
       page <- doGet(makeURL(word.url)) 
       word.morphs <- parse.word(page) 
       df <- append(df, morphToList(word.morphs)) 
     } 
     return(df) 
    } 

    saveWords <- function(df, fileName) { 
     write.table(file = fileName, x = df, append = T, row.names = F, col.names = F, quote = T, sep = ',') 
    } 

    url_base <- 'http://slovonline.ru' 
    url_addr <- makeURL('/slovar_sostav') 
    agent<-"Mozilla/5.0" 

    curl<-getCurlHandle() 
    curlSetOpt(curl = curl, cookiejar='cookies.txt', useragent='Mozilla/5.0', followlocation=T) 


    index <- doGet(url_addr) 
    lrs.url <- xpathSApply(index, "//div[@class = 'nletters all']/a", xmlGetAttr, 'href') 

    for (letter in lrs.url[1:2]) { 
     page <- doGet(makeURL(letter)) 
     table <- parsePage(page) 
     pages.url <- c(letter, xpathSApply(page, "//div[@class = 'npages']/a", xmlGetAttr, 'href')) 
     saveWords(df = table, fileName = 'words.csv') 
     for (page.url in pages.url) { 
       page <- doGet(makeURL(page.url)) 
       table <- parsePage(page) 
       saveWords(df = table, fileName = 'words.csv') 
     } 
    } 

回答

4

XML包已知具有存儲器管理問題,如St​​ackOverflow的查詢揭示了(實施例hereherehere)。 Duncan Lang,包裝的作者和維護者,最遠達到writing paper about memory usage issues

您可以嘗試Hadley Wickham的xml2軟件包,該軟件包承諾比XML更好的內存管理。我個人並沒有證實這一說法。

最後一次當我不得不抓取大量的網頁數據(大約20k頁)時,我決定用Python重寫整個東西。當時沒有xml2

我試過的另一種方法是從shell循環啓動R腳本。這種方式rsession過程在耗盡內存之前已停止。它工作得相當好,雖然相當笨拙。

如果你有興趣,有算法的概述:

  • 在外殼:
    • 檢查是special-name文件存在
    • 如果不存在的話,R上的腳本文件運行r
    • 重複
  • In從「尚未成形的過程」池地址[R腳本
    • 獲取樣品
    • 如果樣本爲空(「尚未到進程」池爲空) - 與special-name(信號外殼停止執行創建文件),並完成
    • 爲每個地址:過程,並從「尚未成形的過程」池中刪除它