文档章节

爬虫初探(二)解析crawler4j源码crawler包

l
 lvzhongjian
发布于 2016/04/03 21:58
字数 1354
阅读 566
收藏 5

        本人也是菜鸟一枚,现在刚开始接触爬虫,想通过读别人的爬虫框架源码来了解下爬虫,如有错误,请见谅并指出。        

        继之前解析了crawler4j的robotstxt包之后,今天来让我们看看crawler包和exception包。

        crawler包中主要有以下几个类:

            1.Configurable:抽象配置类,这是一个抽象类,里面有一个CrawlConfig的引用。其他什么也没有了。

            2.CrawlConfig:这是一个爬虫的具体配置类,里面有许多参数,这里我只介绍几个主要的可配置的参数。

  • resumableCrawling:这个变量用来控制那些已经停止的爬虫是否可以恢复。(开启了会让爬的效率降低)

  • maxDepthOfCrawling:所爬取的最大深度。第一个页面是0的话,则从该页面里获取到的下一个页面深度就是1,以此类推,达到最大深度后的页面下的url都不会加入url队列。

  • maxPagesToFetch:最多的爬取数量。 

  • politenessDelay:发送2个请求的间隔时间

  • includeBinaryContentInCrawling和processBinaryContentInCrawling:是否处理二进制内容,如图像。

  • userAgentString:爬虫名

  • proxyHost和proxyPort:代理服务器地址和端口。(关于代理可以自行百度,简单说下,就是你的爬虫先向代理服务器发送http请求,若代理服务器上有最新结果直接返回,否则由代理服务器向web服务器发送并得到结果返回)

        还有一些参数就不一一讲了。(有些http连接和超时的参数,还有些没搞懂,如onlineTldListUpdate)  

                3.WebCrawler:爬虫类,实现了Runnable。既然实现了Runnable这里首先来看下run方法

 public void run() {
    onStart();
    while (true) {
      List<WebURL> assignedURLs = new ArrayList<>(50);
      isWaitingForNewURLs = true;
      frontier.getNextURLs(50, assignedURLs);
      isWaitingForNewURLs = false;
      if (assignedURLs.isEmpty()) {
        if (frontier.isFinished()) {
          return;
        }
        try {
          Thread.sleep(3000);
        } catch (InterruptedException e) {
          logger.error("Error occurred", e);
        }
      } else {
        for (WebURL curURL : assignedURLs) {
          if (myController.isShuttingDown()) {
            logger.info("Exiting because of controller shutdown.");
            return;
          }
          if (curURL != null) {
            curURL = handleUrlBeforeProcess(curURL);
            processPage(curURL);
            frontier.setProcessed(curURL);
          }
        }
      }
    }
  }

     onStart()方法默认是空方法,但我们可以重写这个方法定制在爬虫开始前的一些配置。然后自己的队列里没有url了就从全局url队列里取,若也没有则结束爬虫。若有url且控制器未关闭则处理,最后告诉全局url控制器Frontier这个url处理过了。

    接着我们来看下处理页的方法,这里贴出主要逻辑

fetchResult = pageFetcher.fetchPage(curURL);//获取结果集
Page page = new Page(curURL);//new 一个page
page.setFetchResponseHeaders(fetchResult.getResponseHeaders());
page.setStatusCode(statusCode);
//status code is 200
if (!curURL.getURL().equals(fetchResult.getFetchedUrl())) {
      if (docIdServer.isSeenBefore(fetchResult.getFetchedUrl())) {
            throw new RedirectException(Level.DEBUG, "Redirect page: " + curURL + " has already been seen");
      }
      curURL.setURL(fetchResult.getFetchedUrl());
      curURL.setDocid(docIdServer.getNewDocID(fetchResult.getFetchedUrl()));
}
parser.parse(page, curURL.getURL());//解析到page中
ParseData parseData = page.getParseData();
for (WebURL webURL : parseData.getOutgoingUrls()) {
int newdocid = docIdServer.getDocId(webURL.getURL());
          if (newdocid > 0) {//对于已经访问过的,深度设置为-1
            // This is not the first time that this Url is visited. So, we set the depth to a negative number.
            webURL.setDepth((short) -1);
            webURL.setDocid(newdocid);
}else {//加入url队列          
            webURL.setDocid(-1);
            webURL.setDepth((short) (curURL.getDepth() + 1));
            if (shouldVisit(page, webURL)) {//满足访问要求,我们可以重写此方法定制自己要访问的页面
                webURL.setDocid(docIdServer.getNewDocID(webURL.getURL()));
                toSchedule.add(webURL);
            }
}
//加入全局url队列
frontier.scheduleAll(toSchedule);
//重写此方法处理获取到的html代码
visit(page);

    里面有许多细节忽略了,不过一次状态码为200的http请求处理过程大致是这样了。

            4.Page:代表一个页面,存储了页面的相关信息

            5.CrawlController:爬虫控制器。这是一个总控制器,用来开启爬虫并监视各个爬虫状态。构造函数需要CrawlConfig,PageFetcher和RobotstxtServer。通过addSeed(String)方法来添加种子(最一开始爬虫所爬的页面),可添加多个。然后通过start方法开始爬取。start方法需要传递一个继承WebCrawler的类的Class对象和开启爬虫的数量。让我们来看下这个start方法

     for (int i = 1; i <= numberOfCrawlers; i++) {//创建爬虫
        T crawler = crawlerFactory.newInstance();
        Thread thread = new Thread(crawler, "Crawler " + i);
        crawler.setThread(thread);
        crawler.init(i, this);
        thread.start();
        crawlers.add(crawler);
        threads.add(thread);
        logger.info("Crawler {} started", i);
      }
      //接下来开启一个监视线程,
      Thread monitorThread = new Thread(new Runnable() {

        @Override
        public void run() {
          try {
            synchronized (waitingLock) {

              while (true) {
                sleep(10);
                boolean someoneIsWorking = false;
                for (int i = 0; i < threads.size(); i++) {//检查每个爬虫
                  Thread thread = threads.get(i);
                  if (!thread.isAlive()) {
                    if (!shuttingDown) {//重启爬虫
                      logger.info("Thread {} was dead, I'll recreate it", i);
                      T crawler = crawlerFactory.newInstance();
                      thread = new Thread(crawler, "Crawler " + (i + 1));
                      threads.remove(i);
                      threads.add(i, thread);
                      crawler.setThread(thread);
                      crawler.init(i + 1, controller);
                      thread.start();
                      crawlers.remove(i);
                      crawlers.add(i, crawler);
                    }
                  } else if (crawlers.get(i).isNotWaitingForNewURLs()) {
                    someoneIsWorking = true;
                  }
                }
                boolean shut_on_empty = config.isShutdownOnEmptyQueue();
                //没有爬虫在工作且,队列为空时关闭
                if (!someoneIsWorking && shut_on_empty) {
                  // Make sure again that none of the threads
                  // are
                  // alive.
                  logger.info("It looks like no thread is working, waiting for 10 seconds to make sure...");
                  sleep(10);

                  someoneIsWorking = false;
                  //再次检查各个线程爬虫
                  for (int i = 0; i < threads.size(); i++) {
                    Thread thread = threads.get(i);
                    if (thread.isAlive() && crawlers.get(i).isNotWaitingForNewURLs()) {
                      someoneIsWorking = true;
                    }
                  }
                  if (!someoneIsWorking) {
                    if (!shuttingDown) {
                    //队列里还有要爬取的页面
                      long queueLength = frontier.getQueueLength();
                      if (queueLength > 0) {
                        continue;
                      }
                      logger.info(
                          "No thread is working and no more URLs are in queue waiting for another 10 seconds to make " +
                          "sure...");
                      sleep(10);
                      //又判断了一次,这里进行了2次判断,防止出现伪结束
                      queueLength = frontier.getQueueLength();
                      if (queueLength > 0) {
                        continue;
                      }
                    }
                    //所有爬虫都结束了,关闭各个服务
                    logger.info("All of the crawlers are stopped. Finishing the process...");
                   
                    frontier.finish();
                    for (T crawler : crawlers) {
                      crawler.onBeforeExit();
                      crawlersLocalData.add(crawler.getMyLocalData());
                    }

                    logger.info("Waiting for 10 seconds before final clean up...");
                    sleep(10);

                    frontier.close();
                    docIdServer.close();
                    pageFetcher.shutDown();

                    finished = true;
                    waitingLock.notifyAll();
                    env.close();

                    return;
                  }
                }
              }
            }
          } catch (Exception e) {
            logger.error("Unexpected Error", e);
          }
        }
      });

      monitorThread.start();

        其实还有许多细节没有解析,不得不佩服大神啊,光是看看都觉得太厉害了。不过还是希望能从这里学到些东西的。

© 著作权归作者所有

l
粉丝 1
博文 14
码字总数 9646
作品 0
苏州
私信 提问
爬虫初探(一)crawler4j的robots

最近刚刚开始研究爬虫,身为小白的我不知道应该从何处下手,网上查了查,发现主要的开源java爬虫有nutch apache/nutch · GitHub,Heritrix internetarchive/heritrix3 · GitHub和Crawler4j...

lvzhongjian
2016/03/31
510
0
Crawler4j的使用

Crawler4j的使用 (以下内容全部为转载,供自己查阅用) 下载地址: http://code.google.com/p/crawler4j/ Crawler4j的使用 网上对于crawler4j这个爬虫的使用的文章很少,Google到的几乎没有...

帅的不像男的
2016/06/07
681
0
liinux/crawler4j

#--------------------------------------------------------------------------------- #说明:源码地址 #https://github.com/yasserg/crawler4j #此项目目的仅为学习此源代码。 #学习样例代......

liinux
2016/08/18
0
0
java爬虫系列(一)——爬虫入门

爬虫框架介绍 java爬虫框架非常多,比如较早的有Heritrix,轻量级的crawler4j,还有现在最火的WebMagic。 他们各有各的优势和劣势,我这里顺便简单介绍一下吧。 Heritrix 优势 java的第一批爬...

Mr_OOO
2017/12/31
0
0
玩大数据一定用得到的19款 Java 开源 Web 爬虫

网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引...

两味真火
2016/09/23
17.1K
12

没有更多内容

加载失败,请刷新页面

加载更多

用 4G 工作是什么体验

七月开始,因为工作原因,在公司附近租了个住处,方便工作。离公司近了,感觉就是不一样,之前每天 5:30 就要起床赶地铁,现在可以睡到自然醒,一看才 7 点,悠闲的起床洗漱,踱步到公司,都...

zzxworld
45分钟前
5
0
sonar报错volatile

问题发生 原先代码如下: //认证授权码private static volatile String AUTHORIZATION_CODE = "init"; git push 之后,sonar认为这是个bug检测报告截图如下: 分析排查 解释说明: Markin...

开源小菜鸟2333
49分钟前
4
0
《Java实践指南》--读后

闲读《Java实践指南》... 1.lvy 某些项目中能够看到ivy.xml。早期使用ant的项目中,常常用ivy.xml来下载项目依赖。 2.ant 作为java程序员,应该都知道ant,虽然可能用过的人不多。为什么ant...

RippleChan
51分钟前
4
0
前端:固定表格(table)表头的实现方式

在写插件 bootstrap table 的时候,当数据过多的时候,需要对表格的 thead 进行固定,然后滚动表格的 tbody 。但是在实际的操作上,花了很多的时间在这个问题上,到现在也没有找到完美的解决...

前端老手
52分钟前
6
0
第五章 spring-connet之AnnotationConfigUtils

前言 AnnotatedBeanDefinitionReader是AnnctionConfig相关上下文与AnnotationConfigUtils的桥梁。还有一个作用是解析class成为BeanDefinitionHolder,注册到容器里面。AnnotationConfigUtils...

鸟菜啊
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部