小小最近开始学习webmagic相关的内容,由于批量爬取的链接将会放入到内存中,将会产生OOM,所以,由此需要把数据放入redis中,确保redis实现其能爬取。
总体介绍
webmagic是一个开源的java垂直爬虫框架,目标简化爬虫的开发流程,让开发者专注于逻辑功能的开发。
采用模块化,覆盖爬虫的全部的生命周期,实现多线程抓去,分布式抓去,并支持自动重试,等功能。
架构简介
分为这四大组件 Downloader、PageProcessor、Scheduler、Pipeline 并进行相关的组织起来。
对这四个组件进行详细的解释。
Downloader
此组件负责从互联网上下载页面,进行后续的处理,采用了apache httpClient作为下载工具。
PageProcessor
此组件负责解析页面,抽取能用的信息,发现新的链接,使用jsoup作为html解析工具,基于xpath的工具,xsoup,作为页面进行相关的解析。
Scheduler
此组件负责,待抓取的URL,以及进行相关的去重,在这里,默认是使用JDK的内存队列实现,同时也支持使用Redis,实现分布式的管理。
其分布式和核心在于对Scheduler进行相关的改造。
Pipeline
此连接定义了结果保存的方式,需要对结果保存的时候,就定制pipeline
构建单机爬虫
这里构建单机的爬虫。
这个爬虫用于构建单机的爬虫。
添加相关依赖文件
<dependencies>
<dependency>
<groupId>us.codecraft</groupId>
<artifactId>webmagic-core</artifactId>
<version>0.7.3</version>
</dependency>
<dependency>
<groupId>us.codecraft</groupId>
<artifactId>webmagic-extension</artifactId>
<version>0.7.3</version>
</dependency>
<dependency>
<groupId>us.codecraft</groupId>
<artifactId>webmagic-extension</artifactId>
<version>0.7.3</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
添加相关的日志文件
log4j.rootLogger=WARN, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
编写相关的爬虫程序
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.pipeline.ConsolePipeline;
import us.codecraft.webmagic.pipeline.JsonFilePipeline;
import us.codecraft.webmagic.processor.PageProcessor;
public class BaiduPageProcessor implements PageProcessor {
private Site site = Site.me()
.setRetryTimes(1)
.setSleepTime(1000)
.setCharset("utf-8");
public void process(Page page) {
page.putField("title", page.getHtml().css("title", "text").toString());
}
public Site getSite() {
return site;
}
public static void main(String[] args) {
Spider.create(new BaiduPageProcessor())
.addUrl("http://www.baidu.com/")
.addPipeline(new ConsolePipeline())
.addPipeline(new JsonFilePipeline("/Users/qmp/myproject/WebMagicSpider"))
.thread(1)
.run();
}
}
执行程序
控制台输出
get page: http://www.baidu.com/
title: 百度一下,你就知道
此时完成了一个单机版的爬虫程序的搭建。
分布式构建
由于当抓取的URL数量过多,会导致出现OOM,所以此时把数据保存进入Redis中,实现分布式构建。
设置Scheduler参数
这里设置Scheduler相关的参数为Redis相关的参数。
spider.setScheduler(new RedisScheduler(jedisPool));
这里需要传入相关的redis参数。即 JedisPool
如果是Spring Boot 相关,需要设置相关的RedisConfig配置类。
@Configuration
public class RedisConfig {
@Value("{spring.redis.host}")
private String host;
@Value("{spring.redis.port}")
private int port;
@Value("{spring.redis.password}")
private String password;
@Value("{spring.redis.timeout}")
private int timeout;
@Value("{spring.redis.jedis.pool.max-idle}")
private int maxIdle;
@Value("{spring.redis.jedis.pool.max-wait}")
private long maxWaitMillis;
@Bean
public JedisPool redisPoolFactory() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
return new JedisPool(jedisPoolConfig, host, port, timeout, password);
}
}
实现分布式爬取
查看源码
这里先查看一段关于run的源码
public void run() {
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 {
// ......
}
}
// ......
}
这样就完成了一次分布式的爬取。其中使用redis作为URL的爬取队列,实现分布式的爬取。