Webmagic控制爬取深度

偶尔善良 提交于 2020-02-26 02:01:30

 

最近搞毕业设计,使用到了webmagic,但是才开始学习,对各个组件都还不是很熟悉。相信初学者都会遇到一个问题,那就是:必须要让所有URL都处理完,才能结束整个爬虫过程吗?

当然,动动脑筋就知道当然不用,但是作为新手还是不知道怎么去控制这个爬虫,我一开始也是只会傻傻的设置一个最开始的url,然后写processs方法。但是经过不断的百度,渐渐加深了对webmagic的理解,也开始看起源码来了。

这两篇文章算是非常有启发的

https://www.zhihu.com/question/46394779

https://bbs.csdn.net/topics/391952114

 

经过源码的查看,大致理清楚了spider的执行流程:入口是Spider.run(); 之后spider首先下载(并不是真正的下载),生成一个page对象,里面包含了网页的信息, 这一部分使用的是downloader的组件,然后就是开始process,使用的是 processer组件,而我们编写的process方法就是在这里被调用的,而我们写的process方法里面,最终要的是addTargetRequest这个方法,使用这个可以再将新的爬取网页加入队列,由于有新的request加入队列,process方法会在下一次循环执行,process完之后就是pipeline,进行一些下载或者存储,例如在pipeline里面我们可以将数据存到数据库,之后开始循环,直到队列为空。我们的修改就可以request这里开始。

addTargetRequest是将一个request加入了队列里面,这样下次就能取到这个request,那么我们只需要对request进行判断,只有在一定条件才能push进去就行了,request对象是有一个extra的,它可以设置数据,然后还可以取出来。

这里我们找到源码中的最关键函数,它是将request加入队列的地方(在QueueScheduler.class  FileCacheQueueScheduler.class 这样的类里面):

protected void pushWhenNoDuplicate(Request request, Task task) {
        if (!this.inited.get()) {
            this.init(task);
        }

        this.queue.add(request);
        this.fileUrlWriter.println(request.getUrl());
    }

最后贴上我修改的代码

int startDepth = 1; //这是自己新增的变量,表示层数
        int levelLimit = 3;
        protected void pushWhenNoDuplicate(Request request, Task task) {
            if (!this.inited.get()) {   //如果还是一个新的对象
                this.init(task);

                Map<String,Object> extras = new HashMap<String,Object>();
                extras.put("depth",this.startDepth);
                request.setExtras(extras);
            }
            else{           //深度的解释: 1表示是最开始的深度,每往下+1
                int currentDepth = (int) request.getExtra("depth");   //获取当前的深度
                if ( currentDepth > this.levelLimit ){   //如果超出了深度限制,则不能再继续了
                    return;
                }
            }
            this.queue.add(request);
            this.fileUrlWriter.println(request.getUrl());
        }

 

 当然,在process方法里面也要有修改,就是一开始获取request的深度,加1就是子节点的深度

int newDepth = (int)page.getRequest().getExtra("depth")+1;  //通过该界面的深度,推算出子界面的深度
        Map<String,Object> newMap = new HashMap<String, Object>();
        newMap.put("depth",newDepth);
        for ( Selectable selectable:aList ){        //对每个链接遍历

            String newURL = selectable.links().toString();
            if ( judgeURL(newURL) == true ) {           //判断URL是否合法
                Request newRequest = new Request();
                newRequest.setExtras(newMap);
                newRequest.setUrl(newURL);
                page.addTargetRequest(newRequest);      //这里加了一个newRequest,之前写的是加URL
            }
        }

 

 

以上就是控制深度的方法,写的很简略。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!