webmagic的源码分析-核心流程和组件

概述:WebMagic的结构分为DownloaderPageProcessorSchedulerPipeline四大组件,并由Spider将它们彼此组织起来。这四大组件对应爬虫生命周期中的下载、处理、管理和持久化等功能。

webmagic 的启动类时Spider,启动时run()方法运行时,会进行初始化各种组件,然后循环运行,从scheduler中取request,包装成runnable,进行请求处理。这个流程中,Scheduler组件负责去重和装待处理的请求,Downloader组件负责下载请求结果包装成page类, pageProcessor组件负责处理page结果,并且可以从page中添加需要采集的另外url,用page.resultItems装处理的结果数据,给Pipeline组件处理结果。

具体使用请看官方文档http://webmagic.io/docs/zh/,或搜索相关案例,本篇主要是对webmagic的源码解析。

    一、流程分析

1、主要方法    

public void run() {
    	// 检查运行状态,并且compareAndSet成运行
        checkRunningStat();
        // 初始化组件
        initComponent();
        logger.info("Spider {} started!",getUUID());
        // 当前线程非中断,运行状态持续运行。
        while (!Thread.currentThread().isInterrupted() && stat.get() == STAT_RUNNING) {
            final Request request = scheduler.poll(this);
            if (request == null) {
                if (threadPool.getThreadAlive() == 0 && exitWhenComplete) {
                    break;
                }
                // wait until new url added
                waitNewUrl();
            } else {
                threadPool.execute(new Runnable() {
                    @Override
                    public void run() {
                        try {
                        	// 处理请求,下载page,pageProcess处理page,pipeline处理page
                            processRequest(request);
                            onSuccess(request);
                        } catch (Exception e) {
                            onError(request);
                            logger.error("process request " + request + " error", e);
                        } finally {
                            pageCount.incrementAndGet();
                            signalNewUrl();
                        }
                    }
                });
            }
        }
        // 设置状态为停止
        stat.set(STAT_STOPPED);
        if (destroyWhenExit) {
            close();
        }
        logger.info("Spider {} closed! {} pages downloaded.", getUUID(), pageCount.get());
    }

      从上面可以看出,Spider就是协调各种组件执行,核心逻辑是从scheduler中取出request包装成任务交由线程池运行,几个主要的组件就是在这个流程中负责各自运行的职责。

   2)初始化组件initComponent

protected void initComponent() {
        if (downloader == null) { // 默认Downloader为HttpClientDownloader
            this.downloader = new HttpClientDownloader();
        }
        if (pipelines.isEmpty()) { // 默认Pipeline为ConsolePipeline
            pipelines.add(new ConsolePipeline());
        }
        downloader.setThread(threadNum);
        if (threadPool == null || threadPool.isShutdown()) {
            if (executorService != null && !executorService.isShutdown()) {
                threadPool = new CountableThreadPool(threadNum, executorService);
            } else {
                threadPool = new CountableThreadPool(threadNum); // 线程池为CountableThreadPool包装
            }
        }
        if (startRequests != null) { // 初始添加请求到scheduler, 默认scheduler为QueueScheduler
            for (Request request : startRequests) {
                addRequest(request);
            }
            startRequests.clear();
        }
        startTime = new Date();
    }

 几个核心组件的的初始实现downloader-HttpClientDownloader、pipelines-ConsolePipeline、scheduler-QueueScheduler pageProcessor-手动制定。

 3、处理请求方法processRequest

private void processRequest(Request request) {
        Page page = downloader.download(request, this); // 下载-即通过HttpClient下载页面,并且构建Page对象。
        if (page.isDownloadSuccess()){ // 下载成功
            onDownloadSuccess(request, page);
        } else { // 失败循环
            onDownloaderFail(request);
        }
    }

 // 下载成功处理

    private void onDownloadSuccess(Request request, Page page) {
        if (site.getAcceptStatCode().contains(page.getStatusCode())){
            pageProcessor.process(page); // 先用pageProcessor处理page
            extractAndAddRequests(page, spawnUrl); // 提取添加的request
            if (!page.getResultItems().isSkip()) { // 如果没有设置isSkip
                for (Pipeline pipeline : pipelines) { 
                    pipeline.process(page.getResultItems(), this); // 多个pipelines处理结果
                }
            }
        }
        sleep(site.getSleepTime());
        return;
    }

  下载成功的处理逻辑,就是进过pageProcessor进行处理page,然后提取addTragetRequest添加到scheduler中,然后在判断是否设置了isSkip,如果没有,那么就用多个pipelines进行结果的处理。

///下载失败的处理

 private void onDownloaderFail(Request request) {
        if (site.getCycleRetryTimes() &#
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值