当前位置: 首页 > 工具软件 > WebCollector > 使用案例 >

WebCollector 爬虫解析

颜楚青
2023-12-01

WebCollector 爬虫解析

  1. WebCollection 爬虫核心类 cn.edu.hfut.dmic.webcollector.crawler.Crawler
	protected int status;  //运行状态 
    public final static int RUNNING = 1;// 运行状态 运行中
    public final static int STOPED = 2; // 运行状态 停止
    protected boolean resumable = false;// 是否中断可恢复,即程序中断是否重新爬取已爬取的网址
    protected int threads = 50;// 爬取的线程树


    protected CrawlDatums seeds = new CrawlDatums(); // 爬区的种子URL集合
    protected CrawlDatums forcedSeeds = new CrawlDatums();// 强制注入 爬区的种子URL集合
    protected Fetcher fetcher;// 爬取任务执行器,管理爬虫线程,调度
    protected int maxExecuteCount = -1; // 设置每个爬取任务的最大执行次数,爬取或解析失败都会导致执行失败。 当一个任务执行失败时,爬虫会在后面的迭代中重新执行该任务,当该任务执行失败的次数超过最大执行次数时,任务生成器会忽略该任务

    protected Executor executor = null;// 实际获得内容并处理的执行器
    protected NextFilter nextFilter = null;// URL爬取后获得的url 过滤器
    protected DBManager dbManager;// 爬取的url存储管理器

其中最重要的方法 开始爬取过程

 /**
     * 开始爬取,迭代次数为depth
     *
     * @param depth 迭代次数
     * @throws Exception 异常
     */
    public void start(int depth) throws Exception {
        LOG.info(this.toString());

        //register dbmanager conf
        ConfigurationUtils.setTo(this, dbManager, executor, nextFilter);

        registerOtherConfigurations();

		// 这里 如果不是可恢复的 清理数据管理器
        if (!resumable) {
            if (dbManager.isDBExists()) {
                dbManager.clear();
            }

            if (seeds.isEmpty() && forcedSeeds.isEmpty()) {
                LOG.info("error:Please add at least one seed");
                return;
            }
        }
        dbManager.open();
		// 向dbManager 注入 种子URL
        if (!seeds.isEmpty()) {
            inject();
        }
		// 向dbManager 强制注入种子URL
        if (!forcedSeeds.isEmpty()) {
            injectForcedSeeds();
        }
		// 状态修改为运行
        status = RUNNING;
        // 开始运行
        for (int i = 0; i < depth; i++) {
            if (status == STOPED) {
                break;
            }
            LOG.info("start depth " + (i + 1));
            long startTime = System.currentTimeMillis();
            // 新建爬取线程执行器
            fetcher = new Fetcher();
           // 配置执行器
            //register fetcher conf
            ConfigurationUtils.setTo(this,fetcher);
		
            fetcher.setDBManager(dbManager);
            fetcher.setExecutor(executor);
            fetcher.setNextFilter(nextFilter);
            fetcher.setThreads(threads);
            // 开始爬取
            int totalGenerate = fetcher.fetchAll(generatorFilter);

            long endTime = System.currentTimeMillis();
            long costTime = (endTime - startTime) / 1000;

            LOG.info("depth " + (i + 1) + " finish: \n\ttotal urls:\t" + totalGenerate + "\n\ttotal time:\t" + costTime + " seconds");
            if (totalGenerate == 0) {
                break;
            }

        }
        // 关闭(这里有一个bug,不知道作者怎么想的, 状态未更改为停止,也未更新为初始值0)
        dbManager.close();
        afterStop();
    }
 
  1. AutoParseCrawler 自动解析爬虫cn.edu.hfut.dmic.webcollector.crawler.AutoParseCrawler extends Crawler implements Executor, Visitor, Requester;
    标识 是否自动解析, 并切实现 Executor实际通过URL 获得页面;
    看其中的增加的属性
	/**
     * 是否自动抽取符合正则的链接并加入后续任务
     */
  	protected boolean autoParse = true;
  	// 爬取到的页面内容 精细化处理, 未实现(个人实现,拿到内容后个人处理)
    protected Visitor visitor;
    // 请求处理器,从URL中获取内容, 默认通过jdk httpConnection
    protected Requester requester;
	// 父类属性复制
    public AutoParseCrawler(boolean autoParse) {
        this.autoParse = autoParse;
        this.requester = this;
        this.visitor = this;
        this.executor = this;
    }
	// Requester 的实现 从URL中获取内容, 默认通过jdk httpConnection
    @Override
    public Page getResponse(CrawlDatum crawlDatum) throws Exception {
        HttpRequest request = new HttpRequest(crawlDatum);
        return request.responsePage();
    }
    /**
     * URL正则约束
     */
    protected RegexRule regexRule = new RegexRule();
   /**
   * Executor 实现,冲datum中url获取内容并处理, 增加到下一个执行任务中
   */
	@Override
    public void execute(CrawlDatum datum, CrawlDatums next) throws Exception {
    	// 获取 datum URL 中的内容,
        Page page = requester.getResponse(datum);
        // 用户处理内容
        visitor.visit(page, next);
        // 如果自动动抽取符合正则的链接并加入后续任务
        if (autoParse && !regexRule.isEmpty()) {
            parseLink(page, next);
        }
        afterParse(page, next);
    }

    protected void parseLink(Page page, CrawlDatums next) {
        String conteType = page.contentType();
        if (conteType != null && conteType.contains("text/html")) {
            Document doc = page.doc();
            if (doc != null) {
                Links links = new Links().addByRegex(doc, regexRule, getConf().getAutoDetectImg());
                next.add(links);
            }
        }

    }


  1. 具体各种dbManager 实现
    BreadthCrawler

/**
 * BreadthCrawler是基于Berkeley DB的插件,于2.20版重新设计
 * BreadthCrawler可以设置正则规律,让遍历器自动根据URL的正则遍历网站,可以关闭这个功能,自定义遍历
 * 如果autoParse设置为true,遍历器会自动解析页面中符合正则的链接,加入后续爬取任务,否则不自动解析链接。
 * 注意,爬虫会保证爬取任务的唯一性,也就是会自动根据CrawlDatum的key进行去重,默认情况下key就是URL,
 * 所以用户在编写爬虫时完全不必考虑生成重复URL的问题。
 * 断点爬取中,爬虫仍然会保证爬取任务的唯一性。
 *
 * @author hu
 */
public abstract class BreadthCrawler extends AutoParseCrawler {

      /**
       * 构造一个基于伯克利DB的爬虫
       * 伯克利DB文件夹为crawlPath,crawlPath中维护了历史URL等信息
       * 不同任务不要使用相同的crawlPath
       * 两个使用相同crawlPath的爬虫并行爬取会产生错误
       * 
       * @param crawlPath 伯克利DB使用的文件夹
       * @param autoParse 是否根据设置的正则自动探测新URL
       */
      public BreadthCrawler(String crawlPath,boolean autoParse) {
        super(autoParse);
        this.dbManager=new BerkeleyDBManager(crawlPath);
    }
    
}

RamCrawler

/**
 * 基于内存的Crawler插件,适合一次性爬取,并不具有断点爬取功能
 * 长期任务请使用BreadthCrawler
 * 
 * @author hu
 */
public abstract class RamCrawler extends AutoParseCrawler {
    
    public RamCrawler(){
        this(true);
    }

    public RamCrawler(boolean autoParse) {
        super(autoParse);
        RamDB ramDB = new RamDB();
        this.dbManager = new RamDBManager(ramDB);
    }
    
    public void start() throws Exception{
        start(Integer.MAX_VALUE);
    }

}

下一篇:任务处理Fetcher

 类似资料: