##簡述 爬蟲在抓取一個頁面後通常有兩個任務,一個是解析頁面內容,一個是將須要繼續抓取的url放入隊列繼續抓取。所以,當爬取的網頁不少的狀況下,待抓取url的管理也是爬蟲框架須要解決的問題。本文主要說的是gecco爬蟲框架的隊列和線程模型。git
##線程和隊列模型 github
- gecco的隊列模型是兩級隊列模型。分爲初始請求隊列和派生請求隊列。初始請求隊列在循環模式下是一個阻塞式的FIFO隊列,在非循環模式下是一個非阻塞式的FIFO隊列。派生隊列是一個非阻塞的剔重的FIFO隊列;
- 線程首先去初始請求隊列按照FIFO原則獲取一個請求,若是線程數量大於初始請求隊列的數量,多餘的線程就會待定新的初始請求入隊,所以建議線程數量不要大於初始請求隊列的數量;
- 對於循環模式loop(true),線程在抓取完成後,會將初始請求從新放入隊列;
- 多線程只對初始請求隊列有效,每一個線程會有本身的派生請求隊列,所以派生請求隊列是在單線程下運行的,爬蟲將派生請求放入隊列繼續抓取,直到沒有派生請求;
- 線程在抓取完成派生請求後,會繼續向初始請求隊列獲取初始請求
##爲何要用這種模型瀏覽器
- Gecco的線程模型很像瀏覽器,每個線程對應一個瀏覽器的Tab。每一個瀏覽器的Tab一次只能看一個頁面,所以就有了初始請求隊列多線程,派生請求隊列單線程的模型。
- 使用這種隊列和線程模型開發人員很好理解,結構簡單易懂,效率也能保證。想用多線程提升效率就想辦法放入初始請求隊列。
##如何動態的獲取初始請求隊列 若是想經過多線程提升爬蟲的效率就須要想辦法將請求放入初始請求隊列。咱們能夠先經過一個爬蟲引擎將待抓取的請求保存起來。另一個爬蟲引擎以第一個爬蟲引擎獲取的請求做爲初始請求開啓多線程運行。簡單說就是初始請求也是能夠抓取出來的,並不必定非要寫死。下面是jd採用多線程抓取的一段代碼,所有代碼已經上傳github。多線程
//先獲取分類列表,放入AllSortPipeline.sortRequests HttpGetRequest start = new HttpGetRequest("http://www.jd.com/allSort.aspx"); start.setCharset("GBK"); GeccoEngine.create() .classpath("com.geccocrawler.gecco.demo.jd") .start(start) .run(); //分類列表下的商品列表採用3線程抓取 GeccoEngine.create() .classpath("com.geccocrawler.gecco.demo.jd") //從上面的GeccoEngine獲取初始請求 .start(AllSortPipeline.sortRequests) .thread(5) .interval(2000) .start();