该事例演示了如何在多线程中统计和分析数据;

 

首先建一个状态实体类CrawlStat:

package com.demo.collectingData;
 
/**
 * 爬虫状态实体类 统计爬虫信息
 * @author
 *
 */
public class CrawlStat {
  private int totalProcessedPages; //处理的页面总数
  private long totalLinks; // 总链接数
  private long totalTextSize; // 总文本长度
 
  public int getTotalProcessedPages() {
    return totalProcessedPages;
  }
 
  public void setTotalProcessedPages(int totalProcessedPages) {
    this.totalProcessedPages = totalProcessedPages;
  }
 
  /**
   * 总处理页面数加1
   */
  public void incProcessedPages() {
    this.totalProcessedPages++;
  }
 
  public long getTotalLinks() {
    return totalLinks;
  }
 
  public void setTotalLinks(long totalLinks) {
    this.totalLinks = totalLinks;
  }
 
  public long getTotalTextSize() {
    return totalTextSize;
  }
 
  public void setTotalTextSize(long totalTextSize) {
    this.totalTextSize = totalTextSize;
  }
 
  /**
   * 总链接数加count个
   * @param count
   */
  public void incTotalLinks(int count) {
    this.totalLinks += count;
  }
 
  /**
   * 总文本长度加total个
   * @param count
   */
  public void incTotalTextSize(int count) {
    this.totalTextSize += count;
  }
}

 

再建一个LocalDataCollectorCrawler类:

package com.demo.collectingData;
 
import java.io.UnsupportedEncodingException;
import java.util.Set;
import java.util.regex.Pattern;
 
import edu.uci.ics.crawler4j.crawler.Page;
import edu.uci.ics.crawler4j.crawler.WebCrawler;
import edu.uci.ics.crawler4j.parser.HtmlParseData;
import edu.uci.ics.crawler4j.url.WebURL;
 
/**
 * 该类演示了如何在多线程中统计和分析数据
 * @author user
 *
 */
public class LocalDataCollectorCrawler extends WebCrawler {
 
  // 正则匹配后缀
  private static final Pattern FILTERS = Pattern.compile(
      ".*(\\.(css|js|bmp|gif|jpe?g|png|tiff?|mid|mp2|mp3|mp4|wav|avi|mov|mpeg|ram|m4v|pdf" +
      "|rm|smil|wmv|swf|wma|zip|rar|gz))$");
 
  CrawlStat myCrawlStat; // 定义爬虫状态对象,用户统计和分析
 
  /**
   * 构造方法
   */
  public LocalDataCollectorCrawler() {
    myCrawlStat = new CrawlStat(); // 实例化爬虫状态对象
  }
  
  /**
   * 这个方法主要是决定哪些url我们需要抓取,返回true表示是我们需要的,返回false表示不是我们需要的Url
   * 第一个参数referringPage封装了当前爬取的页面信息
   * 第二个参数url封装了当前爬取的页面url信息
   */
  @Override
  public boolean shouldVisit(Page referringPage, WebURL url) {
    String href = url.getURL().toLowerCase(); // 获取url小写
    return !FILTERS.matcher(href).matches() && href.startsWith("http://www.xxx.com"); // 必须是www.xxx.com域名
  }
 
  /**
   * 当我们爬到我们需要的页面,这个方法会被调用,我们可以尽情的处理这个页面
   * page参数封装了所有页面信息
   */
  @Override
  public void visit(Page page) {
    System.out.println("正在爬取页面:"+page.getWebURL().getURL());
    myCrawlStat.incProcessedPages(); // 处理页面加1
 
    if (page.getParseData() instanceof HtmlParseData) { // 假如是html数据
      HtmlParseData parseData = (HtmlParseData) page.getParseData(); // 获取Html数据
      Set<WebURL> links = parseData.getOutgoingUrls(); // 获取输出链接
      myCrawlStat.incTotalLinks(links.size()); // 总链接加link.size个
      try {
        myCrawlStat.incTotalTextSize(parseData.getText().getBytes("UTF-8").length); // 文本长度增加
      } catch (UnsupportedEncodingException ignored) {
        // Do nothing
      }
    }
    // 每获取3个页面数据 我们处理下数据
    if ((myCrawlStat.getTotalProcessedPages() % 3) == 0) {
      dumpMyData();
    }
  }
 
  /**
   * 获取下爬虫状态
   */
  @Override
  public Object getMyLocalData() {
    return myCrawlStat;
  }
 
  /**
   * 当任务完成时调用
   */
  @Override
  public void onBeforeExit() {
    dumpMyData(); // 处理处理
  }
 
  /**
   * 处理数据
   */
  public void dumpMyData() {
    int id = getMyId();
    System.out.println("当前爬虫实例id:"+id);
    System.out.println("总处理页面:"+myCrawlStat.getTotalProcessedPages());
    System.out.println("总链接长度:"+myCrawlStat.getTotalLinks());
    System.out.println("总文本长度:"+myCrawlStat.getTotalTextSize());
  }
}

 

最后建一个控制器LocalDataCollectorController:

package com.demo.collectingData;
 
 
import java.util.List;
 
 
import edu.uci.ics.crawler4j.crawler.CrawlConfig;
import edu.uci.ics.crawler4j.crawler.CrawlController;
import edu.uci.ics.crawler4j.fetcher.PageFetcher;
import edu.uci.ics.crawler4j.robotstxt.RobotstxtConfig;
import edu.uci.ics.crawler4j.robotstxt.RobotstxtServer;
 
/**
 * 爬虫控制器
 * @author user
 *
 */
public class LocalDataCollectorController {
 
  public static void main(String[] args) throws Exception {
    
 
    String rootFolder = "c:/crawl"; // 定义爬虫数据存储位置
    int numberOfCrawlers = 2; // 定义7个爬虫,也就是7个线程
 
    CrawlConfig config = new CrawlConfig(); // 定义爬虫配置
    config.setCrawlStorageFolder(rootFolder); // 设置爬虫文件存储位置
    config.setMaxPagesToFetch(10);  // 设置最大页面获取数
    config.setPolitenessDelay(1000); // 设置爬取策略 1秒爬一次
 
    // 实例化爬虫控制器
    PageFetcher pageFetcher = new PageFetcher(config); // 实例化页面获取器
    RobotstxtConfig robotstxtConfig = new RobotstxtConfig(); // 实例化爬虫机器人配置 比如可以设置 user-agent
     
    // 实例化爬虫机器人对目标服务器的配置,每个网站都有一个robots.txt文件 规定了该网站哪些页面可以爬,哪些页面禁止爬,该类是对robots.txt规范的实现
    RobotstxtServer robotstxtServer = new RobotstxtServer(robotstxtConfig, pageFetcher);
     
    // 实例化爬虫控制器
    CrawlController controller = new CrawlController(config, pageFetcher, robotstxtServer);
 
    controller.addSeed("http://www.xxx.com"); // 添加爬虫种子
     
    // 启动爬虫,爬虫从此刻开始执行爬虫任务,根据以上配置
    controller.start(LocalDataCollectorCrawler.class, numberOfCrawlers);
 
    List<Object> crawlersLocalData = controller.getCrawlersLocalData(); // 当多个线程爬虫完成任务时,获取爬虫本地数据
    long totalLinks = 0;
    long totalTextSize = 0;
    int totalProcessedPages = 0;
    for (Object localData : crawlersLocalData) {
      CrawlStat stat = (CrawlStat) localData;
      totalLinks += stat.getTotalLinks();
      totalTextSize += stat.getTotalTextSize();
      totalProcessedPages += stat.getTotalProcessedPages();
    }
 
    // 打印数据
    System.out.println("统计数据:");
    System.out.println("总处理页面:"+totalProcessedPages);
    System.out.println("总链接长度:"+totalLinks);
    System.out.println("总文本长度:"+totalTextSize);
  }
}

打印结果:

正在爬取页面:http://www.xxx.com/
正在爬取页面:http://www.xxx.com/share/2814499085634560.htm
正在爬取页面:http://www.xxx.com/share/2519215530527744.htm
正在爬取页面:http://www.xxx.com/share/2783070349888512.htm
当前爬虫实例id:2
总处理页面:3
总链接长度:672
总文本长度:22295
正在爬取页面:http://www.xxx.com/share/2769260213275648.htm
正在爬取页面:http://www.xxx.com/share/kredis-p1-s1.htm
正在爬取页面:http://www.xxx.com/share/kswing-p1-s1.htm
当前爬虫实例id:2
总处理页面:6
总链接长度:1299
总文本长度:46674
正在爬取页面:http://www.xxx.com/share/kcodehaus-p1-s1.htm
正在爬取页面:http://www.xxx.com/user/2176279510861824.htm
正在爬取页面:http://www.xxx.com/blog/2881413902666752.htm
当前爬虫实例id:2
总处理页面:9
总链接长度:1617
总文本长度:90618
当前爬虫实例id:1
总处理页面:1
总链接长度:326
总文本长度:10321
当前爬虫实例id:2
总处理页面:9
总链接长度:1617
总文本长度:90618
统计数据:
总处理页面:10
总链接长度:1943
总文本长度:100939