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