摘要:實際運行中就發(fā)現(xiàn)了一個有趣的現(xiàn)象。爬蟲抓取的速度超過了我用給它推送的速度,導(dǎo)致爬蟲從獲取不到同時此刻線程池所有線程都已停止。如何管理設(shè)置,避免返回,且沒有工作線程時退出循環(huán)。退出檢測循環(huán)說明結(jié)束了,手動調(diào)用來是退出調(diào)度循環(huán),終止爬蟲。
Webmagic源碼分析系列文章,請看這里
從解決問題開始吧。
問題描述:由于數(shù)據(jù)庫的數(shù)據(jù)量特別大,而且公司沒有搞主從讀寫分離,導(dǎo)致從數(shù)據(jù)庫讀取數(shù)據(jù)比較慢,而我需要從數(shù)據(jù)庫查詢出特定標識來拼url去抓。實際運行中就發(fā)現(xiàn)了一個有趣的現(xiàn)象。爬蟲抓取的速度超過了我用scheduler給它推送url的速度,導(dǎo)致爬蟲從scheduler獲取不到url,同時此刻線程池所有線程都已停止。這個時候,根據(jù)Spider的機制是要退出調(diào)度循環(huán)的,從而終止Spider。從下面代碼可以看出:(取自Spider的run方法):
while ((!(Thread.currentThread().isInterrupted())) && (this.stat.get() == 1)) { Request request = this.scheduler.poll(this); if (request == null) { if ((this.threadPool.getThreadAlive() == 0) && (this.exitWhenComplete)) { break; } waitNewUrl(); } else { Request requestFinal = request; this.threadPool.execute(new Runnable(requestFinal) { public void run() { try { Spider.this.processRequest(this.val$requestFinal); Spider.this.onSuccess(this.val$requestFinal); } catch (Exception e) { Spider.this.onError(this.val$requestFinal); Spider.this.logger.error("process request " + this.val$requestFinal + " error", e); } finally { Spider.this.pageCount.incrementAndGet(); Spider.this.signalNewUrl(); } } }); } } this.stat.set(2); if (this.destroyWhenExit) close();
上述中,由于Spider默認exitWhenComplete=true,而this.threadPool.getThreadAlive() == 0也在我剛剛描述的場景中應(yīng)驗了,所以此時Spider會break退出調(diào)度循環(huán),進而終止。
那么如何解決呢?我們應(yīng)該注意到了exitWhenComplete這個標志,Spider是開放了這個標志的setter的,那么我們可以通過它來實現(xiàn)自定義的管理。如何管理?
//設(shè)置exitWhenComplete=false,避免scheduler.poll返回null,且沒有工作線程時退出循環(huán)。 spider.setExitWhenComplete(false); spider.start(); //分頁循環(huán)推送url int i=2; while(i<=page.getTotalPages()){ page=storeManager.findPage(c, i, 50); for(Store s:page.getResult()){ if(StringUtils.isNotBlank(s.getSkipLink()) && s.getSkipLink().contains("?id=")){ Request request=new Request(s.getSkipLink()); scheduler.push(request,spider); } } i++; } int nullCount=0; //分5次重試來確保真的沒有了。 while(nullCount<5){ //如果沒有活動線程,我們就查看scheduler中是否有request,如果沒有,計數(shù)+1,之后休眠再重新循環(huán)。 if(spider.getThreadAlive()==0){ Request req=scheduler.poll(spider); if(req==null){ nullCount++; }else{ if(nullCount>0){ nullCount=0; } scheduler.push(req, spider); } } HttpReqUtil.sleep(5*60*1000); } //退出檢測循環(huán)說明結(jié)束了,手動調(diào)用stop()來是Spider退出調(diào)度循環(huán),終止爬蟲。 spider.stop();
其實,如果你想Spider池化,也可以采用這個思路來。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/69916.html
摘要:爬蟲框架源碼分析之爬蟲框架源碼分析之爬蟲框架源碼分析之爬蟲框架源碼分析之爬蟲框架源碼分析之之進階 爬蟲框架Webmagic源碼分析之Spider爬蟲框架WebMagic源碼分析之Scheduler爬蟲框架WebMagic源碼分析之Downloader爬蟲框架WebMagic源碼分析之Selector爬蟲框架WebMagic源碼分析之SeleniumWebMagic之Spider進階
摘要:獲取正在運行的線程數(shù),用于狀態(tài)監(jiān)控。之后初始化組件主要是初始化線程池將到中,初始化開始時間等。如果線程池中運行線程數(shù)量為,并且默認,那么就停止退出,結(jié)束爬蟲。 本系列文章,針對Webmagic 0.6.1版本 一個普通爬蟲啟動代碼 public static void main(String[] args) { Spider.create(new GithubRepoPageP...
摘要:包主要實現(xiàn)類,這是一個抽象類,實現(xiàn)了通用的模板方法,并在方法內(nèi)部判斷錯誤重試去重處理等。重置重復(fù)檢查就是清空,獲取請求總數(shù)也就是獲取的。至于請求總數(shù)統(tǒng)計,就是返回中維護的的大小。 Scheduler是Webmagic中的url調(diào)度器,負責(zé)從Spider處理收集(push)需要抓取的url(Page的targetRequests)、并poll出將要被處理的url給Spider,同時還負責(zé)...
摘要:方法,首先判斷是否有這是在中配置的,如果有,直接調(diào)用的將相應(yīng)內(nèi)容轉(zhuǎn)化成對應(yīng)編碼字符串,否則智能檢測響應(yīng)內(nèi)容的字符編碼。 Downloader是負責(zé)請求url獲取返回值(html、json、jsonp等)的一個組件。當然會同時處理POST重定向、Https驗證、ip代理、判斷失敗重試等。 接口:Downloader 定義了download方法返回Page,定義了setThread方法來...
摘要:是爬蟲框架中比較簡單易上手的一個。官網(wǎng)鏈接下面的例子是使用這個框架來爬取工商銀行的私人理財推薦分頁列表數(shù)據(jù)。頁面鏈接為引入配置如果項目已經(jīng)引入記錄日志,則需要在中排除。 webmagic是java爬蟲框架中比較簡單易上手的一個。官網(wǎng)鏈接:http://webmagic.io/ 下面的例子是使用這個框架來爬取工商銀行的私人理財推薦分頁列表數(shù)據(jù)。頁面鏈接為:https://mybank.i...
閱讀 3052·2021-11-16 11:45
閱讀 5427·2021-09-22 10:57
閱讀 1831·2021-09-08 09:36
閱讀 1717·2021-09-02 15:40
閱讀 2566·2021-07-26 23:38
閱讀 1305·2019-08-30 15:55
閱讀 993·2019-08-30 15:54
閱讀 1279·2019-08-29 14:06