最近搞毕业设计,使用到了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
}
}
以上就是控制深度的方法,写的很简略。
来源:CSDN
作者:Bowen_Yang
链接:https://blog.csdn.net/qq_39627843/article/details/104446165