zoukankan      html  css  js  c++  java
  • webmagic自定义存储(mysql、redis存储)

    在很多时候,我们使用webmagic爬取网站的时候,爬取的数据希望存储在mysql、redis中。因此需要对其扩展,实行自定义PipeLine。首先我们了解一下webmagic 的四个基本组件

    一、 WebMagic的四个组件

    1、Downloader

    Downloader负责从互联网上下载页面,以便后续处理。WebMagic默认使用了HttpClient作为下载工具。

    2、PageProcessor

    PageProcessor负责解析页面,抽取有用信息,以及发现新的链接。WebMagic使用Jsoup作为HTML解析工具,并基于其开发了解析XPath的工具Xsoup。

    在这四个组件中,PageProcessor对于每个站点每个页面都不一样,是需要使用者定制的部分。

    3、Scheduler

    Scheduler负责管理待抓取的URL,以及一些去重的工作。WebMagic默认提供了JDK的内存队列来管理URL,并用集合来进行去重。也支持使用Redis进行分布式管理。

    除非项目有一些特殊的分布式需求,否则无需自己定制Scheduler。

    4、Pipeline

    Pipeline负责抽取结果的处理,包括计算、持久化到文件、数据库等。WebMagic默认提供了“输出到控制台”和“保存到文件”两种结果处理方案。

    Pipeline定义了结果保存的方式,如果你要保存到指定数据库,则需要编写对应的Pipeline。对于一类需求一般只需编写一个Pipeline。

    二、自定义Pipeline,实现Pipeline接口,从写process方法。

    package com.mdd.pip.pipeLine;
    
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import com.mdd.pip.model.ProxyIp;
    import com.mdd.pip.service.ProxyIpService;
    
    import us.codecraft.webmagic.ResultItems;
    import us.codecraft.webmagic.Task;
    import us.codecraft.webmagic.pipeline.Pipeline;
    
    @Component
    public class DataPipeLine implements Pipeline {
    
        @Autowired
        private ProxyIpService proxyIpService;
    
        /**
         * mysql 存储
         */
        /*
         * public void process(ResultItems resultItems, Task task) {
         * List<ProxyIp>proxyIpList = resultItems.get("proxyIpList");
         * if(proxyIpList!=null&&!proxyIpList.isEmpty()){
         * proxyIpService.saveProxyIpList(proxyIpList); }
         * 
         * }
         */
    
        /**
         * redis 存储
         */
        public void process(ResultItems resultItems, Task task) {
            List<ProxyIp> proxyIpList = resultItems.get("proxyIpList");
            if (proxyIpList != null && !proxyIpList.isEmpty()) {
                proxyIpService.saveProxyListIpInRedis(proxyIpList);
            }
    
        }
    }
    ResultItems 对象本质是一个Map。因此要我们保存对象的时候,只需要在爬取时把爬取得数据封装成对象,保存在
    ResultItems 里即可。如果有很多数据,则可以考虑用List保存。
    package com.mdd.pip.crawler;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.apache.log4j.Logger;
    import org.jsoup.nodes.Document;
    import org.jsoup.nodes.Element;
    import org.jsoup.select.Elements;
    import org.springframework.stereotype.Component;
    
    import com.mdd.pip.model.ProxyIp;
    import us.codecraft.webmagic.Page;
    import us.codecraft.webmagic.Site;
    import us.codecraft.webmagic.processor.PageProcessor;
    
    /**
     * 热刺代理网站ip抓取
     * 
     * @author xwl 2017.6.3
     */
    @Component
    public class XiCiProxyIpCrawler implements PageProcessor {
    
        private Logger logger = Logger.getLogger(XiCiProxyIpCrawler.class);
    
        // 部分一:抓取网站的相关配置,包括编码、抓取间隔、重试次数等
        private Site site = Site.me().setCycleRetryTimes(3).setRetryTimes(3).setSleepTime(1000)
                .setUserAgent("Mozilla/5.0 (Windows NT 6.1; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0");
    
        public Site getSite() {
            return site;
        }
    
        
        public void process(Page page) {
            Document html = page.getHtml().getDocument();
            // 结果集
            List<ProxyIp> proxyIpList = new ArrayList<ProxyIp>();
            Elements trElements = html.getElementById("ip_list").getElementsByTag("tr");
            for (Element trEle : trElements) {
                Elements tdElements = trEle.getElementsByTag("td");
                if (tdElements == null||tdElements.size()<=0) {
                    continue;
                }
                try {
                    ProxyIp proxyIp = new ProxyIp();
                    String ip = tdElements.get(1).text();
                    String proxyPort = tdElements.get(2).text();
                    String ipAddress = tdElements.get(3).text();
                    String anonymity = tdElements.get(4).text();
                    String proxyType = tdElements.get(5).text();
                    String aliveTime = tdElements.get(6).text();
                    proxyIp.setProxyIp(ip);
                    proxyIp.setProxyPort(Integer.parseInt(proxyPort));
                    proxyIp.setAliveTime(aliveTime);
                    proxyIp.setAnonymity(anonymity);
                    proxyIp.setIpAddress(ipAddress);
                    proxyIp.setProxyType(proxyType);
                    logger.info(proxyIp.getProxyIp()+":"+proxyIp.getProxyPort());
                    proxyIpList.add(proxyIp);
                } catch (Exception e) {
                    logger.error("IP代理解析出错!", e);
                }
            }
            page.putField("proxyIpList", proxyIpList);
        }
    }
    page.putField("proxyIpList", proxyIpList);本质是设值到了ResultItems对象里了。

    这样插件式、定制化很值的我们借鉴。希望下一步看源码。

    参考:
    http://webmagic.io/docs/zh/posts/ch1-overview/architecture.html
  • 相关阅读:
    JavaScript DOM API初步(整理)
    MySQL与Oracle之间互相拷贝数据的Java程序
    MySQL与Oracle的区别之我见
    js原生:封装document.getElementByClassName()函数
    js和jquery获取父级元素、子级元素、兄弟元素的方法
    封装bt轮播图淡入淡出效果样式
    Bootstrap每天必学之导航条
    全面解析Bootstrap图片轮播效果
    JS如何获取页面可见区域高度
    怎样才能成为优秀的前端工程师
  • 原文地址:https://www.cnblogs.com/xwlmdd/p/7045930.html
Copyright © 2011-2022 走看看