2016-01-21 81 views
1

我正在爲具有越來越多的實體的網站實施爬網程序。沒有可用的信息有多少實體存在,沒有所有實體的列表。每個實體都可以用這樣的URL訪問:http://www.somewebsite.com/entity_{i}其中{i}是實體的編號,從1開始並遞增1.多線程與未知數量的任務

要檢索我正在運行的每個實體,檢查HTTP請求是否返回一個200404。如果我得到404 NOT FOUND,循環停止,並且我確定我擁有所有實體。如果成功,假如果它有一個404 NOT FOUND錯誤

def atTheEnd = false 
def i = 0 
while(!atTheEnd){ 
    atTheEnd = !crawleWebsite("http://www.somewebsite.com/entity_" + i) 
    i++ 
} 

crawleWebsite()返回true:

串行的方式看起來是這樣的。

問題是爬行的實體可能需要很長的,這就是爲什麼我想要做的多線程,但我不知道實體的總量所以每次任務不是獨立於其他任務。

最好的解決方法是什麼?

我的做法是這樣的:使用與REST HEAD請求二進制搜索,獲得實體總數(500和1000之間),並分裂那些某些線程。

這樣做有沒有更好的方法?

TL;博士

基本上我想講一個線程池以編程方式創建新的任務,直到一個條件滿足時(第一404發生),並等到每個任務完成。

注:我執行使用Grails 3此代碼。

+0

的gpars memoize的例子似乎你在做什麼? http://gpars.org/1.1.0/guide/guide/single.html#dataParallelism_parallelCollections_memoize –

+0

不,據我瞭解,它做了一些不同的事情。我總是爲每個實體爬行一個新頁面,記住緩存頁面供進一步使用。緩存不會幫助我,因爲每個實體都在不同的頁面上。 – Peter

+0

你可以做基本相同的事情,但沒有記憶? –

回答

1

正如你所說的,實體的總數量是未知的,可以去到數千人。在這種情況下,我只需要尋找一個固定的線程池並推測性地查詢URL即使您可能已經達到了最後。考慮這個例子。

@Grab(group = 'org.codehaus.gpars', module = 'gpars', version = '1.2.1') 
import groovyx.gpars.GParsPool 

//crawling simulation - ignore :-) 
def crawleWebsite(url) { 
    println "$url:${Thread.currentThread().name}" 
    Thread.sleep (1) 
    Math.random() * 1000 < 950 
} 

final Integer step = 50 
Boolean atTheEnd = false 
Integer i = 0 
while (true) { 
    GParsPool.withPool(step) { 
     (i..(i + step)).eachParallel{atTheEnd = atTheEnd || !crawleWebsite("http://www.somewebsite.com/entity_" + it)} 
     } 
     if (atTheEnd) { 
      break 
     } 
     i += step 
} 

線程池被設置爲50,一旦所有50個URL被抓取,我們檢查是否到達結尾。如果不是,我們繼續。

顯然,在最壞的情況下你可以爬50 404秒。但我敢肯定,你可以逃脫它:-)

+0

我會盡快嘗試您的解決方案。 :) – Peter