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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM