Java爬虫第11课:webmagic中URL保存与去重
在解析页面的时候,很可能会解析出相同的url地址(例如商品标题和商品图片超链接,而且url一样),如果不进行处理,同样的url会解析处理多次,浪费资源。所以我们需要有一个url去重的功能。
URL保存
WebMagic提供了Scheduler可以帮助我们解决以上问题。
Scheduler是WebMagic中进行URL管理的组件。一般来说,Scheduler包括两个作用:
1)对待抓取的URL队列进行管理。
2)对已抓取的URL进行去重。
WebMagic内置了几个常用的Scheduler。如果你只是在本地执行规模比较小的爬虫,那么基本无需定制Scheduler,但是了解一下已经提供的几个Scheduler还是有意义的。
DuplicateRemovedScheduler
抽象基类,提供一些模板方法,继承它可以实现自己的功能
QueueScheduler
使用内存队列保存待抓取URL
PriorityScheduler
使用带有优先级的内存队列保存待抓取URL,耗费内存较QueueScheduler更大,但是当设置了request.priority之后,只能使用PriorityScheduler才可使优先级生效
FileCacheQueueScheduler
使用文件保存抓取URL,可以在关闭程序并下次启动时,从之前抓取到的URL继续抓取,需指定路径,会建立.urls.txt和.cursor.txt两个文件
RedisScheduler(开发最常用)
使用Redis保存抓取队列,可进行多台机器同时合作抓取(分布式),需要安装并启动redis
URL去重
去重部分被单独抽象成了一个接口:DuplicateRemover,从而可以为同一个Scheduler选择不同的去重方式,以适应不同的需要,目前提供了两种去重方式。
HashSetDuplicateRemover
使用HashSet来进行去重,占用内存较大
BloomFilterDuplicateRemover
使用BloomFilter来进行去重,占用内存较小,但是可能漏抓页面。
RedisScheduler是使用Redis的set进行去重,其他的Scheduler默认都使用HashSetDuplicateRemover来进行去重。
如果要使用BloomFilter,必须要加入以下依赖:
<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> <!--WebMagic对布隆过滤器的支持--> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>16.0</version> </dependency>
修改代码,添加布隆过滤器
public static void main(String[] args) { Spider.create(new JobProcessor()) //初始访问url地址 .addUrl("https://www.jd.com/moreSubject.aspx") .addPipeline(new FilePipeline("D:/webmagic/")) .setScheduler(new QueueScheduler() .setDuplicateRemover(new BloomFilterDuplicateRemover(10000000))) //参数设置需要对多少条数据去重 .thread(1)//设置线程数 .run(); }
修改public void process(Page page)方法,添加一下代码
//每次加入相同的url,测试去重 page.addTargetRequest("https://www.jd.com/news.html?id=36480");
打开布隆过滤器BloomFilterDuplicateRemover,在下图处打断点测试
完整代码:
package com.jiagou1216.crawler.test; import us.codecraft.webmagic.Page; import us.codecraft.webmagic.Site; import us.codecraft.webmagic.Spider; import us.codecraft.webmagic.processor.PageProcessor; import us.codecraft.webmagic.scheduler.BloomFilterDuplicateRemover; import us.codecraft.webmagic.scheduler.QueueScheduler; import us.codecraft.webmagic.scheduler.Scheduler; /** * @author 架构师小跟班 * @Description: https://www.jiagou1216.com * @date 2020/7/16 15:38 */ public class JobProcessor implements PageProcessor { //解析页面 public void process(Page page) { //解析返回的数据page,并且把解析的结果放到ResultItems中 //css选择器 page.putField("div", page.getHtml().css("div.mt h2").all()); //XPath page.putField("div2", page.getHtml().xpath("//div[@id=news_div]/ul/li/div/a")); //正则表达式 page.putField("div3", page.getHtml().css("div#news_div a").regex(".*江苏.*").all()); //处理结果API page.putField("div4", page.getHtml().css("div#news_div a").regex(".*江苏.*").get()); page.putField("div5", page.getHtml().css("div#news_div a").regex(".*江苏.*").toString()); //获取链接 //page.addTargetRequests(page.getHtml().css("div#news_div").links().regex(".*9$").all()); //page.putField("url",page.getHtml().css("div.mt h1").all()); page.addTargetRequest("https://www.jd.com/news.html?id=37319"); page.addTargetRequest("https://www.jd.com/news.html?id=37319"); page.addTargetRequest("https://www.jd.com/news.html?id=37319"); } private Site site = Site.me() .setCharset("utf8") //设置编码 .setTimeOut(10000) //设置超时时间,单位是ms毫秒 .setRetrySleepTime(3000) //设置重试的间隔时间 .setSleepTime(3); //设置重试次数 public Site getSite() { return site; } //主函数,执行爬虫 public static void main(String[] args) { Spider spider = Spider.create(new JobProcessor()) .addUrl("https://www.jd.com/moreSubject.aspx") //设置爬取数据的页面 //.addPipeline(new FilePipeline("C:\\Users\\tree\\Desktop\\result")) .thread(5) //设置布隆去重过滤器,指定最多对1000万数据进行去重操作 .setScheduler(new QueueScheduler().setDuplicateRemover(new BloomFilterDuplicateRemover(10000000))); Scheduler scheduler = spider.getScheduler(); //执行爬虫 spider.run(); } }