前言
如果还没有阅读前序文章,可以移步到:简单爬虫设计(一)——基本模型
基本概念
爬取范围(Crawling Scope)是爬虫的输入,是爬取任务(Crawling Task)的一部分。爬取范围作为统一语言的一部分,可以让模型更易读。
统一语言,是领域驱动设计引入的一个重要概念,统一语言让业务方和开发方能够使用一套词汇进行沟通,好的领域模型也可以充当统一语言。
在该系列的第一篇文章简单爬虫设计(一)——基本模型 中,对爬取范围进行了显式建模,并讨论了爬取范围需要包含的数据项,这里再简单回顾一下每个数据项的含义。
- 起始网址(爬取深度为0)
- 从起始网址开始要遍历的链接最大深度,也称为采集深度或最大跳数
- 要遍历的链接特征
- 遍历链接数量最大值
- 是否只采集域名内链接等
在具体实现的时候,链接特征需要考虑到各种复杂情况,这里先只考虑字符串特征和正则表达式特征。
举个例子
下面用一个具体例子来说明这些数据项的用法。
- 我们假设要爬取一个博客网站,比如酷壳网。
- 起始网址可以设置为网站首页地址https://coolshell.cn。
- 根据这个网站的特点,采集深度可以设置为3,基本可以遍历到所有历史文章。
- 要遍历的链接可以是站内所有链接,如果用正则表达式表示的话,可以是https://coolshell\.cn/.+,其中的“.+”表示匹配任意字符。需要说明,遍历的链接并不是最终要保存或者继续处理的链接。
- 遍历的链接数量最大值可以不设置,意味着不限制数量。
- 设置只采集域名内的链接。如果设置了需要遍历的链接特征,这个设置就没有用了,可以忽略。
通过这个例子,基本可以了解爬取范围的设置了。下面来看具体的实现代码。
代码示例
interface CrawlingScope { //接口定义
List<String> startUrls();
boolean contains(Link link);
long maxToCrawl();
int maxHops();
}
class CrawlingScopeImpl { //实现类
//起始URL,第0跳
private List<String> startUrls;
//从起始URL开始计算跳数
private int maxHops;
//指定正则表达式规则的URL会继续爬取
private String urlCrawlRegex;
//包含特定字符串特征的URL会继续爬取
private String urlCrawlStrPattern;
//最多爬取多少页面
private long maxToCrawl = Long.MAX_VALUE;
//限制到起始URL的域名
private boolean restrictDomain;
public boolean contains(Link link) {
String url = link.getUrl();
for (String startUrl : this.startUrls) {
if (link.getUrl().equalsIgnoreCase(startUrl)) {
return true;
}
}
if (link.getDepth() > this.maxHops) {
return false;
}
if (this.restrictDomain && !isUnderDomain(url)) {
return false;
}
UrlFilter urlFilter = new UrlFilter(
this.urlCrawlStrPattern, this.urlCrawlRegex);
return urlFilter.isMatch(url);
}
}
使用CrawlingScope的代码示例。
public void crawl(){
fetchAndProcess(target); //爬取并处理
//如果爬取链接总数大于最大限制
if (this.fetchedLinks.total() >= crawlingScope.maxToCrawl()) {
return;
}
//省略部分代码
if (this.crawlingScope.contains(link) && //链接在爬取范围内
!this.fetchedLinks.contains(link)) { //如果链接还没被爬取过
targetLinks.add(link); //加入待爬取集合
}
}
小结
以上就是爬取范围的设计和实现。通过对爬取范围进行显式建模,能够让相关概念聚集在一起,爬虫的设计和实现也更加清晰。下一篇文章将实现ProcessingScope,也就是需要处理的网页范围。