架构师

您现在的位置是:首页 > 程序人生 > 网络爬虫

网络爬虫

Java爬虫第11课:webmagic中URL保存与去重

架构师小跟班 2020-07-16 网络爬虫
在解析页面的时候,很可能会解析出相同的url地址(例如商品标题和商品图片超链接,而且url一样),如果不进行处理,同样的url会解析处理多次,浪费资源。所以我们需要有一个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();
    }
}


文章评论