WebMagicのSpider進級

3686 ワード

Webmagicソース分析シリーズの記事は、ここを参照してください.
問題解決から始めましょう.
問題の説明:データベースのデータ量が特に大きいため、会社は主に読み書きから分離していないため、データベースからデータを読み取るのが遅いので、私はデータベースから特定の識別をクエリーしてurlをつづる必要があります.実際の運行で興味深い現象が発見された.爬虫類の捕獲速度は、私がschedulerでurlをプッシュする速度を超えており、爬虫類がschedulerからurlを取得できないと同時に、スレッドプールのすべてのスレッドが停止しています.このとき,Spiderのメカニズムによりスケジューリングループを終了し,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も先ほど説明したシーンで当てはまるので、Spiderはbreakがスケジューリングループを終了し、終了します.
では、どのように解決すればいいのでしょうか.このフラグはexitWhenCompleteというフラグに注目すべきで、Spiderはこのフラグのsetterを開いているので、カスタマイズされた管理を実現することができます.管理方法
                //  exitWhenComplete=false,  scheduler.poll  null,            。
                spider.setExitWhenComplete(false);
                spider.start();
                //      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,    ,  +1,         。
                    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);
                }
                //           ,    stop()  Spider      ,    。
                spider.stop();

実は、Spiderをプール化したいなら、この考え方を採用することもできます.