Java爬虫——WebMagic多线程,多深度数据爬取整合

WebMagic——多线程,多深度数据爬取整合

注:

此文章主要解决以下应用场景,在使用webmagic框架时,会存在多线程爬取数据,这就导致了在不同页面中爬取到的数据无法整合为一条,因为你在爬取A页面的时候,你其实也在爬取通过A页面点进去的B页面,但是这其实是一条数据,应该在存储时进行整合。

相关Demo文件
正则表达式解析

应用场景:

这是A页面,也就是第一层页面,通多A页面点击 “北京岭秀” 进入B页面

在这里插入图片描述

进入如下B页面后,需要抓取,楼盘的别名,以及标题,而且需要通过查看更多楼盘详情,进入C页面

在这里插入图片描述

进入C页面后,我需要抓取他的基本信息,那么如何将C页面的数据与B整合呢,解决思路如下:

在这里插入图片描述

思路:

创建一个Map,以抓取的跳转c页面的链接作为Key,以B页面的数据作为value进行绑定,让后存入Request 中,在匹配到是C页面时,在通过自己本身的url进行获取,尽可以拿到指定的value,从而保证了数据的一致性

代码:

package com.jyft.wf.test;

import com.jyft.wf.webmagic.MyPipeline;

import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Request;
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 java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author:wf
 * @Date 2021/6/16 16:56
 * @Describe:抓取贝壳数据并整合Demo
 **/
public class Test01 implements PageProcessor {
    //楼盘列表页
    private static String   startUrl="https://bj.fang.ke.com/loupan/pg1";
    //详情页url
    private static String   pageUrl="https://bj\\.fang\\.ke\\.com/loupan/p_\\w+/";
    //最里面的详细信息url
    private static String   detailedPageUrl="https://bj\\.fang\\.ke\\.com/loupan/p_\\w+/xiangqing/";



    private Site site = Site.me()
            //设置字符集,此处使用的字符集应该和网站使用的字符集相同,不然就会出现乱码的情况
            .setCharset("utf8")
            //设置超时时间为10s
            .setTimeOut(10*1000)
            //重试间隔时间为3S
            .setRetrySleepTime(3000)
            //重试次数为 3次
            .setRetryTimes(3)
            ;
    @Override
    public void process(Page page) {


        //判断是否为列表的url
        if(page.getUrl().regex("https://bj.fang.ke.com/loupan/pg.*").match()) {
            //获取单个楼盘详情页连接
            List<String> all = page.getHtml().css("ul.resblock-list-wrapper").links().regex("https://bj.fang.ke.com/loupan/.*").all();
            for (String comicUrl : all) {
                //这种形式可以设置优先级
                //Request request = new Request(comicUrl).setPriority(1);
                Request request = new Request(comicUrl);
                page.addTargetRequest(request);
            }
            //添加分页的楼盘页链接
            for(int i=2; i<3; i++){
                //这种形式可以设置优先级
               // Request request = new Request("https://bj.fang.ke.com/loupan/pg"+i+"/").setPriority(0);
                Request request = new Request("https://bj.fang.ke.com/loupan/pg"+i+"/");
                page.addTargetRequest(request);
            }




            //https://bj.fang.ke.com/loupan/p_bjlxafsft/?fb_expo_id=460899605006036992
            //https://bj.fang.ke.com/loupan/p_thsayhafsmo/?fb_expo_id=460899605006036993
            //https://bj.fang.ke.com/loupan/p_gtydafsys/?fb_expo_id=460899605006036994

            //判断是第三层最里面的详细信息页面(此页面获取楼盘所有详细信息),
            // 通过本次的url来获取刚刚第二层中存入Request中的数据,从而保证了数据的一致性
        }else if((page.getUrl().regex(detailedPageUrl).match())){

            String sectionUrl = page.getUrl().toString();
            //获取对象数据
            Map<String,Object> urlNameMap=(Map<String,Object>)page.getRequest().getExtra("urlNameMap");
            //通过url获取对应指定的那个项目的数据
            Map<String,Object> dataObj=( Map<String,Object>)urlNameMap.get(sectionUrl);
            if(dataObj==null){
                page.setSkip(true);
            }
            //获取楼盘的详细信息数据
            String style = page.getHtml().css("div.big-left ul.x-box li.all-row span.label-val", "text").toString();
            System.out.println("真正的详细信息数据:"+style);
            dataObj.put("物业类型",style);
            page.putField("data",dataObj);

         //判断是否为第二层,(此页面只获取楼盘名称,并存储,便于第三层数据对应使用)
        }else if((page.getUrl().regex(pageUrl).match())){

            //获取楼盘名称
            String text = page.getHtml().css("h2.DATA-PROJECT-NAME", "text").toString();
            //楼盘别名
            String text1 = page.getHtml().css("div.other-name", "text").toString();
            //将此处获取的信息存起来
            Map<String,Object> dataObj=new HashMap<>();
            dataObj.put("name",text);
            dataObj.put("name2",text1);

            //获取更多的鏈接,即第三层的连接
            List<String> all1 = page.getHtml().css("div.more-building").links().all();
            System.out.println("查看详细信息的链接--》"+all1);

            //将每条第三层的连接和对应的数据绑定起来,再存入Request,等进入第三层页面的时候,再通过url指定获取对应的数据
            Map<String,Object> urlNameMap=new HashMap<>();
            for (String comicUrl : all1) {
                //通过url绑定数据
                urlNameMap.put(comicUrl,dataObj);
                //此处也是设置优先级的写法
               //Request request = new Request(comicUrl).setPriority(2);
                Request request = new Request(comicUrl);
                //将当前数据存入Request
                request.putExtra("urlNameMap", urlNameMap);
                page.addTargetRequest(request);
            }
            System.out.println("绑定数据:"+urlNameMap);

            System.out.println("----------------------------------------------------------");

        }



    }

    @Override
    public Site getSite() {
        return site;
    }

    public static void main(String[] args) {
        //程序抓取的入口
        Spider.create(new Test01())
                //从这个url开始抓取
                .addUrl(startUrl)
                //设置使用布隆过滤器去重
                .setScheduler(new QueueScheduler().setDuplicateRemover(new BloomFilterDuplicateRemover(10000000)))
                //设置10个线程同时抓取
                .thread(10)
                //使用自己的Pipeline将结果保存到数据库中
                .addPipeline(new MyPipeline())
                .run();

    }
}
  • 一些注意的点
    1.爬虫启动后无法进入process方法,可能是因为使用了布隆过滤器,或者redis对url进行了去重,删除掉之前的url即可
    这一块的资料较少,本人也是查找了很久,希望对大家有所帮助,可以少走一些弯路
  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亿只王菜菜

各位爷,赏口饭吃吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值