2017-02-13 73 views
1

我試圖從我已經存儲在一個數組中的一堆HTML頁面拉一個字符串。我有以下代碼:處理內存時使用節點和jsdom蜘蛛網站

const jsdom = require('jsdom') 
desc('Import pages'); 
task('handleSpots', [], function (params) { 

    allSpots.forEach(function(spotUrl){ 
    handleSpot(spotUrl) 
    }) 
}); 

function handleSpot (href) { 
    jsdom.env(
    href, 
    ["http://code.jquery.com/jquery.js"], 
    function (err, window) { 
     if (err) { 
     console.log(host+href+" "+err) 
     return 
     } 
     const data = {url: host+href} 
     data['name'] = window.$("h1.wanna-item-title-title a").text() 
     console.log(data['name']) 
     window.close() 
    } 
); 
} 

allSpots數組中有大約600個URL。當我運行此,我收到了一堆錯誤:

/the_hook/index.html Error: read ECONNRESET 

這正好一堆網址,顯示一些名字,最後我得到這個錯誤。

<--- Last few GCs ---> 

80660 ms: Scavenge 1355.3 (1460.0) -> 1355.3 (1460.0) MB, 2.3/0 ms (+ 1.4 ms in 1 steps since last GC) [allocation failure] [incremental marking delaying mark-sweep]. 
82149 ms: Mark-sweep 1355.3 (1460.0) -> 1354.8 (1460.0) MB, 1488.7/0 ms (+ 2.8 ms in 2 steps since start of marking, biggest step 1.4 ms) [last resort gc]. 
83657 ms: Mark-sweep 1354.8 (1460.0) -> 1354.6 (1460.0) MB, 1508.2/0 ms [last resort gc]. 


<--- JS stacktrace ---> 

==== JS stack trace ========================================= 

Security context: 0x38f1b4237339 <JS Object> 
    1: create [native v8natives.js:~755] [pc=0x22e6902f1923] (this=0x38f1b4236b61 <JS Function Object (SharedFunctionInfo 0x38f1b4236ad1)>,an=0x1590d58f6941 <an Object with map 0x1b19e3c1e251>,aD=0x38f1b4204131 <undefined>) 
    2: arguments adaptor frame: 1->2 
    3: createImpl [/Users/craig/Programming/node_wannasurf_importer/node_modules/jsdom/lib/jsdom/living/generated/Text.js:~90] [pc=0x22e... 

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory 
Abort trap: 6 

只有當allSpots數組中有超過125個項目時纔會發生這種情況。少於這一點,一切正常。

我對節點很新,但我假設Javascript試圖在同一時間獲取太多這些頁面,並最終耗盡內存。理想情況下,我可以寫的東西處理100,等到這樣做了,然後移動到下一個100

我嘗試這樣做: async.eachLimit(allSpots,100,handleSpot) 但是,只處理第100然後停止。

我也試過: async.eachSeries(allSpots,handleSpot) 但是這隻處理第一個url並停止。

我處於死路一條,所以我非常感謝任何人都可以給我的建議。 謝謝,

克雷格

回答

1

我決定放棄jsdom與cheerio和HTTPS取代它,這樣我可能會請求過程中多一點控制。然後我研究瞭如何同步請求每個url(在請求上使用on('end')),然後開始在一個循環中處理urls,所以循環迭代的次數是併發進程的數量。

下面的代碼:

const https = require('https'); 
const cheerio = require('cheerio') 

desc('Import pages'); 
task('handleSpots', [], function (params) { 
    var totalLoop = 10; 
    for(var i = 0; i < totalLoop; i++) { 
    handleSpotAndNext() 
    } 
}); 

function handleSpotAndNext() { 
    spot = allSpots.pop() 
    https.get(spot,function(res){ 
    var chunks = ''; 
    res.on('data',function(d){ 
     chunks += d; 
    }); 
    res.on('end',function(){ 
     console.log(spotData(chunks, spot)) 
     if(allSpots.length){ 
     handleSpotAndNext(); 
     } 
    }) 
    }) 

} 

function spotData(spotHtml, url) { 
    $ = cheerio.load(spotHtml) 
    const data = {url: url} 
    data['name'] = $("h1.wanna-item-title-title a").text() 
    return data 
} 

這是我想出了,但如果你看到這一點,能想到更好的解決方案的它會是巨大的,從你的來信。