Java爬虫 WebCollector 教程——去重辅助插件 NextFilter

注意:对于95%的爬虫任务,没有必要定制NextFilter插件,爬虫自身的去重机制可以应付大部分的任务。NextFilter是一个高级去重插件,往往应用在用户需要依赖自己的数据库进行去重的场景。另外,使用NextFilter之前请仔细阅读该教程,它可能与你见过的其它爬虫的去重插件完全不是同一个东西。

作用

NextFilter的功能是:帮助爬虫过滤探测到的URL信息。

WebCollector在爬取过程中自带了去重的功能,NextFilter是一个用于过滤的插件,与爬虫自带的去重功能无关。

例如,用WebCollector定制一个爬取CSDN博客的程序时很容易的,但某个开发者遇到的情况是,他的同事之前用其他的爬虫已经采集了50万篇CSDN博客,放到了业务用的MYSQL中,但是现在这位开发者需要编写新的爬虫,在编写新爬虫时不希望爬虫采集那50万篇已经采集的博客,然而新的爬虫的去重库里并没有这50万篇博客的URL。这时NextFilter就派上用场了,新的爬虫自身可以保证在爬取CSDN时不进行重复爬取,定制一个NextFilter,用于过滤掉爬虫探测到的URL中与那50万篇CSDN博客URL重复的部分,就可以保证新的爬虫:

  • 爬虫自身不重复爬取
  • 爬虫不爬取业务库中已有的50万篇博客

插件编写

编写NextFilter插件时,只需新建一个实现NextFilter接口的类即可:

并覆盖其中的public CrawlDatum filter(CrawlDatum nextItem, CrawlDatum referer)方法即可:

public static class MyNextFilter implements NextFilter{
  /**
  * @param nextItem 被探测到的URL
  * @param referer 被探测到的URL所在的页面
  * @return 如果希望过滤nextItem,返回null,否则返回nextItem
  */
  @Override
  public CrawlDatum filter(CrawlDatum nextItem, CrawlDatum referer) {
    //如果希望过滤nextItem,返回null,否则返回nextItem
  }
}

下面这个例子使用NextFilter对爬虫探测到的URL进行过滤,代码通过将autoParse设置为true和addRegex(".*")让爬虫自动探测网页中所有的URL,该例子加入了一个自定义的NextFilter对这些URL进行过滤,只有满足”http://blog.csdn.net/./article/details/.“这个正则的URL才被保留。

import cn.edu.hfut.dmic.webcollector.fetcher.NextFilter;
import cn.edu.hfut.dmic.webcollector.model.CrawlDatum;
import cn.edu.hfut.dmic.webcollector.model.CrawlDatums;
import cn.edu.hfut.dmic.webcollector.model.Page;
import cn.edu.hfut.dmic.webcollector.plugin.berkeley.BreadthCrawler;

/**
 * @author hu
 */
public class DemoNextFilter extends BreadthCrawler {

    /*
        该例子利用WebCollector 2.50新特性NextFilter过滤探测到的URL
     */
    public DemoNextFilter(String crawlPath, boolean autoParse) {
        super(crawlPath, autoParse);
        addSeed("http://blog.csdn.net/");
        addRegex(".*");
        //设置线程数
        setThreads(30);
    }

    @Override
    public void visit(Page page, CrawlDatums next) {
        if (page.matchType("content")) {
            String title = page.select("div[class=article_title]").first().text();
            String author = page.select("div[id=blog_userface]").first().text();
            System.out.println("title:" + title + "\tauthor:" + author);
        }
    }

    public static void main(String[] args) throws Exception {
        DemoNextFilter crawler = new DemoNextFilter("crawl", true);
        crawler.setNextFilter(new NextFilter() {
            @Override
            public CrawlDatum filter(CrawlDatum nextItem, CrawlDatum referer) {
                if (nextItem.matchUrl("http://blog.csdn.net/.*/article/details/.*")) {
                    nextItem.type("content");
                    return nextItem;
                } else {
                    return null;
                }
            }
        });
        crawler.start(2);
    }

}

对于新手,不要完全依赖NextFilter插件进行去重

一些新手看了教程后可能会想通过Redis和NextFilter来实现自己的去重插件,例如有人会采用这种方案:“当过滤器接收到一个URL时,查询Redis,如果Redis中有这个URL,过滤器不过滤这个URL,并将其加入Redis中,如果Redis中不包含这个URL,则过滤该URL”,这是一个错误且非常幼稚的方案,因为:

  • WebCollector会自己实现去重,不要多此一举
  • 上述方案是错误的,因为在多线程环境下,如果要保证程序的错误,要将引号内的整个流程上锁,这会导致爬虫效率的大大降低。虽然用Redis的一些原子操作可以解决效率的问题,但是何必呢,爬虫还是要自己再进行去重的。

一个常用的NextFilter插件——HashSetNextFilter

一个常见的使用NextFilter的业务,就是已知一些已采集或需要过滤的URL,但这些URL并不在爬虫自带的去重库中时,可通过NextFilter过滤这些已知的URL。将这些已知的URL添加到HashSetNextFilter中并将其设置为爬虫的NextFilter即可直接完成这个功能。

在下面的例子中,通过addRegex方法控制爬虫只会探测到http://geek.csdn.nethttp://lib.csdn.net这两个链接,向HashSetNextFilter中添加了http://geek.csdn.net使得该链接被NextFilter组件过滤,因此最后爬虫只会抓取种子页面和http://lib.csdn.net这两个页面。


import cn.edu.hfut.dmic.webcollector.fetcher.NextFilter; import cn.edu.hfut.dmic.webcollector.model.CrawlDatum; import cn.edu.hfut.dmic.webcollector.model.CrawlDatums; import cn.edu.hfut.dmic.webcollector.model.Page; import cn.edu.hfut.dmic.webcollector.plugin.berkeley.BreadthCrawler; import cn.edu.hfut.dmic.webcollector.plugin.nextfilter.HashSetNextFilter; /** * @author hu */ public class DemoHashSetNextFilter extends BreadthCrawler { /* 该例子利用WebCollector 2.50新特性NextFilter过滤探测到的URL */ public DemoHashSetNextFilter(String crawlPath, boolean autoParse) { super(crawlPath, autoParse); addSeed("http://www.csdn.net"); addRegex("http://geek.csdn.net"); addRegex("http://lib.csdn.net"); //设置线程数 setThreads(30); } @Override public void visit(Page page, CrawlDatums next) { System.out.println("Not Filtered: " + page.doc().title()); } public static void main(String[] args) throws Exception { DemoHashSetNextFilter crawler = new DemoHashSetNextFilter("crawl", true); HashSetNextFilter nextFilter = new HashSetNextFilter(); //this url will be filtered nextFilter.add("http://geek.csdn.net"); //nextFilter.add("http://lib.csdn.net"); crawler.setNextFilter(nextFilter); crawler.start(2); } }

You may also like...

发表评论

电子邮件地址不会被公开。 必填项已用*标注

推荐文章
加QQ群下载完整Eclipse项目

WebCollector网络爬虫:250108697(已满)

WebCollector网络爬虫2群:345054141

热门