本文是 WebMagic 源码阅读第三篇,版本依然是 version-0.0.1 的 tag。作者对于 Scheduler 的描述是如下:

包含url管理和调度的接口。包括url抓取队列,url去重等功能。

阅读Scheduler源码

Scheduler 是一个接口类,源码中实现有三个,分别是

默认 Spider 使用 QueueScheduler

1
2
// 默认使用基于内存的队列
private Scheduler scheduler = new QueueScheduler();

Scheduler 接口只有两个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 加入一个待抓取的链接
* @param request 待抓取的链接
* @param task 定义的任务,以满足单Scheduler多Task的情况
*/
public void push(Request request,Task task);

/**
* 返回下一个要抓取的链接
* @param task 定义的任务,以满足单Scheduler多Task的情况
* @return 下一个要抓取的链接
*/
public Request poll(Task task);

接下来,分析常用的的两个实现类 QueueScheduler 和 RedisScheduler

QueueScheduler

线程安全的队列实现请求的生产消费关系,push 和 poll 都是同步方法,同时因为 LinkedBlockingQueue 的长度是 Integer.MAX_VALUE,如果队列过长,会出现 OOM 的情况。

RedisScheduler

源码中使用 Redis 的 list 结构做 URL 队列,通过 rpush 方法,将新的 URL 放入队列右边,通过 lpop 从队列左侧弹出一个待抓取的 URL 。

使用了 Redis 的有序集合进行 URL 去重,原理是:
如果 url 是有序集和的成员,返回 url 的排名。 如果 url 不是有序集和的成员,返回 null。zrank 方法参数如下:
zrank(有序集合的key, 成员名称)

当成功添加 URL 到队列,调用 zadd 方法将 URL 放入有序集合当中,便于后续 URL 判重。

总结

功力不足,尚且看不出这部分源码的不足之处,只看到 RedisScheduler 中 jedis 释放资源的操作未放到 final 中,有所隐患。

联系

独行的路总是孤独的,希望能找到一些小伙伴共同进步~

QQ 群号:967808880