即使爬虫已经运行,可以控制爬虫。可以控制的内容有

3.1 停止爬虫

VS提供了一个停止爬虫的接口,不过对于VS来说,停止爬虫有多种方法。最官方的做法是调用stopCrawler()方法。但是这个方法不是立即关闭爬虫的,其实任何时候VS都不能做到立即关闭爬虫(即使kill -9也不会)。这是因为VS会尽可能保证数据一致性。爬虫停止首先会刷新缓存包括db数据,bloomFilter信息。如果是主动关闭爬虫,爬虫首先会等待所有正在执行的任务执行结束,然后安静关闭爬虫。

VS的爬虫停止工作做得非常好,不信你可以看如下日志,这是我在开启爬虫之后,强制杀掉爬虫进程打印出来的日志。当你看到‘“爬虫被外部中断,尝试进行资源关闭等收尾工作”字样的时候,证明爬虫是意外停止的,这个时候VS也能尝试进行资源收尾工作

2017-06-24 22:07:48 WARN  [vsCrawler-resource-clean] c.v.v.c.VSCrawler$ResourceCleanHookThread:354>>爬虫被外部中断,尝试进行资源关闭等收尾工作
2017-06-24 22:07:48 INFO  [vsCrawler-resource-clean] c.v.v.c.VSCrawler:110>>爬虫停止,发送爬虫停止事件消息:com.virjar.vscrawler.event.systemevent.CrawlerEndEvent
2017-06-24 22:07:48 WARN  [VSCrawler-Dispatch] c.v.v.c.VSCrawler:151>>爬虫线程休眠被打断
2017-06-24 22:07:48 INFO  [vsCrawler-resource-clean] c.v.v.c.s.BerkeleyDBSeedManager:590>>收到爬虫结束消息,开始关闭资源
2017-06-24 22:07:48 INFO  [vsCrawler-resource-clean] c.v.v.c.s.BerkeleyDBSeedManager:591>>拒绝抓取结果入库...
2017-06-24 22:07:48 INFO  [vsCrawler-resource-clean] c.v.v.c.s.BerkeleyDBSeedManager:593>>缓存中未分发数据重新入库,正在执行的爬虫任务,不等待结果,重新入库...
                      江城子 . 程序员之歌

                  十年生死两茫茫,写程序,到天亮。
                      千行代码,Bug何处藏。
                  纵使上线又怎样,朝令改,夕断肠。

                  领导每天新想法,天天改,日日忙。
                      相顾无言,惟有泪千行。
                  每晚灯火阑珊处,夜难寐,加班狂。
2017-06-24 22:07:48 INFO  [vsCrawler-resource-clean] c.v.v.c.s.BerkeleyDBSeedManager:595>>写入段表信息
2017-06-24 22:07:48 INFO  [vsCrawler-resource-clean] c.v.v.c.s.BerkeleyDBSeedManager:597>>关闭数据库环境...
2017-06-24 22:07:48 INFO  [VSCrawlerWorker-thread-1] c.v.v.c.s.BerkeleyDBSeedManager:352>>db已经关闭,拒绝归还任务
2017-06-24 22:07:48 WARN  [VSCrawlerWorker-thread-1] c.v.v.c.s.BerkeleyDBSeedManager:455>>db已经关闭,拒绝添加新种子
http://www.java1234.com/ 处理完成
2017-06-24 22:07:48 INFO  [VSCrawler-Dispatch] c.v.v.c.VSCrawler:125>>爬虫已经停止,不需要发生爬虫停止事件消息
2017-06-24 22:07:48 INFO  [VSCrawler-Dispatch] c.v.v.c.VSCrawler:187>>爬虫结束
2017-06-24 22:07:56 INFO  [watch-service-thread-1] c.v.v.c.c.DirectoryWatcher:137>>contextPath:work
2017-06-24 22:07:56 INFO  [watch-service-thread-1] c.v.v.c.c.DirectoryWatcher:140>>directoryPath:/Users/virjar/git/vscrawler/vscrawler-samples/target/classes
2017-06-24 22:07:56 INFO  [watch-service-thread-1] c.v.v.c.c.DirectoryWatcher:143>>absolutePath:/Users/virjar/git/vscrawler/vscrawler-samples/target/classes/work
2017-06-24 22:07:56 INFO  [watch-service-thread-1] c.v.v.c.c.DirectoryWatcher:144>>kind:ENTRY_MODIFY
2017-06-24 22:07:56 INFO  [watch-service-thread-1] c.v.v.c.c.DirectoryWatcher:160>>修改:/Users/virjar/git/vscrawler/vscrawler-samples/target/classes/work

3.2 获取当前活跃线程数量

方法签名为 com.virjar.vscrawler.core.VSCrawler#activeWorker 其实就是得到线程池里面活跃线程数目

3.3 清除历史任务数据

对于VS来说,断点续爬是默认实现且必须执行的,如果你是在做测试的话,可能曾经添加过的种子在爬虫任务里面出现过,导致种子会因为消重机制不能重新添加到任务队列里面。这个时候clearTask就是一个很好的方法了。com.virjar.vscrawler.core.VSCrawler#clearTask 在加入种子之前调用这个方法即可清空所有任务

3.4 爬虫启动回调

一般来说,在VS中不需要观察着模式的回调,但是爬虫启动回调很例外,爬虫启动回调是指在爬虫初始化之后,事件机制刚刚工作的时候所做的通知。这是因为之前可能事件机制不可用导致基于事件的回调不生效导致。你可以调用方法 com.virjar.vscrawler.core.VSCrawler#addCrawlerStartCallBack实现此回调。

3.5 慢启动

慢启动是一个很有用的功能,但是默认是关闭的,慢启动的意思是爬虫刚刚开始的时候,不会马上达到最大线程数目。这是因为我们的爬虫可能会集中使用某些资源,而且这个集中程度最可能就是在爬虫刚刚开始的运行的时候,比如你会执行登录,那么可能段时间有几百的帐户在登录,目标网站很容易发现这些帐户的异常。所以开启慢启动之后,爬虫会在一段时间内慢慢的增加线程数目,直到达到配置的线程数目为之。

一个应用场景就是我在使用滑块登录的时候,滑块有着明显的频率限制,所以在刚开始频繁模拟登录产生大量滑块验证码请求而导致滑块验证码识别失败。

3.6 注入种子

通过VS对象添加种子任务,com.virjar.vscrawler.core.VSCrawler#pushSeed(java.lang.String) 或者com.virjar.vscrawler.core.VSCrawler#pushSeed(com.virjar.vscrawler.core.seed.Seed)

3.7 举个栗子

我想实现一个需求,当爬虫连续10秒钟没有新任务了,就停止爬虫,应该如何实现呢?其实VS本身不支持这个功能的,但是我们想要在不修改VS框架源码的基础上实现它也是很简单的。

 vsCrawler.addCrawlerStartCallBack(new VSCrawler.CrawlerStartCallBack() {
            @Override
            public void onCrawlerStart(final VSCrawler vsCrawler) {
                AutoEventRegistry.getInstance().registerEvent(ShutDownChecker.class);
                AutoEventRegistry.getInstance().registerObserver(new ShutDownChecker() {

                    @Override
                    public void checkShutDown() {
                        // 15s之后检查活跃线程数,发现为0,证明连续10s都没用任务执行了
                        if (vsCrawler.activeWorker() == 0
                                && (System.currentTimeMillis() - vsCrawler.getLastActiveTime()) > 10000) {
                            System.out.println("尝试停止爬虫");
                            vsCrawler.stopCrawler();
                        }
                    }
                });
                AutoEventRegistry.getInstance().registerObserver(new SeedEmptyEvent() {
                    @Override
                    public void onSeedEmpty() {// 如果收到任务为空消息的话,尝试停止爬虫
                        // 发送延时消息,当前收到了任务为空的消息,产生一个发生在15s之后发生的事件,
                        AutoEventRegistry.getInstance().createDelayEventSender(ShutDownChecker.class, 15000).delegate()
                                .checkShutDown();
                    }
                });
            }
        });

同时定义一个接口,ShutDownChecker,他的代码如下:

public interface ShutDownChecker {
        @AutoEvent
        void checkShutDown();
    }

首先,我们在爬虫启动后添加一个爬虫回调,回调内容是注册一个事件。同时监听任务为空的消息。SeedEmptyEvent,在SeedEmptyEvent处理逻辑里面,发送一个延时消息,也就是15秒之后检查一下是否满足爬虫停止条件。然后我们直线爬虫停止判断路基,如果15秒后爬虫工作线程数目是0,同时爬虫最后启动的时间距离当前时间超过了10s,那么爬虫至少空转了10s,这时调用stopCrawler的方法,关闭爬虫。

这个demo还是有点绕的,这是VS的风骚代码风格,VS内部大量此类风骚代码,不建议将VS作为入门框架学习,入门VS请先出门左转😄

results matching ""

    No results matching ""