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
时间: 2024-10-19 15:43:52

webmagic自定义存储(mysql、redis存储)的相关文章

python---scrapy之MySQL同步存储

假设我们已经能获取到item里定义的字段的数据,接下来就需要保存item的数据到mysql数据库. pipeline用来存储item中的数据,将爬取到的数据进行二次处理 首先,要做的准备的工作,安装MySQLdb,我安装的是Python-MySQL1.2.5模块. 自定义一个pipeline用mysql来存储item中的数据 class MySQLPipeline(object): #自定义一个pipeline用mysql来存储item中的数据 def __init__(self): # 代码连

键值存储之redis

MySQL通过Memcached将热点数据加载到cache,加速访问,但随着业务数据量的不断增加,和访问量的持续增长会遇到很多问题: 1.MySQL需要不断进行拆库拆表,Memcached也需不断跟着扩容,扩容和维护工作占据大量开发时间. 2.Memcached与MySQL数据库数据一致性问题. 3.Memcached数据命中率低或down机,大量访问直接穿透到DB,MySQL无法支撑. 4.跨机房cache同步问题. 如果简单地比较Redis与Memcached的区别,redis会有如下优点:

redis使用基础(十) ——Redis存储Session

redis使用基础(十) --Redis存储Session (转载请附上本文链接--linhxx) 一.概述 PHP默认是将session存于服务器的文件中.当并发量大,此方式效率低,因此可以采用redis存储session. 要改变session的存储位置,首先要改变php.ini中的配置项session.save_handler,将其值设置为user. 二.改变存储位置函数 php内置的函数session_set_save_handler可以重新设定session的保存方式,包括sessio

redis慢查询日志、php安装redis扩展、redis存储session、redis主从配置

一:redis慢查询日志 编辑配置文件/etc/redis.conf针对慢查询日志,可以设置两个参数,一个是执行时长,单位是微秒,另一个是慢查询日志的长度.当一个新的命令被写入日志时,最老的一条会从命令日志队列中被移除. slowlog-log-slower-than 1000 //单位ms,表示慢于1000ms则记录日志slowlog-max-len 128 //定义日志长度,表示最多存128条slowlog get //列出所有的慢查询日志slowlog get 2 //只列出2条slowl

Redis存储Object 和 list&lt;object&gt;

Redis 存储支持的类型没有object ,虽然有支持list,但是只支持List<String> 有两种方法可以实现存储对象和泛型 1.用序列化和反序列化 2.json 序列化工具类,实现序列化和反序列话对象和list集合 package com; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.Object

利用samba给mysql提供数据存储服务

利用samba部署wordpress (1) samba server导出/data/application/web,在目录中提供wordpress; (2) samba  client挂载nfs server导出的文件系统至/var/www/html: (3) 客户端(lamp)部署wordpress,并让其正常访问:要确保能正常发文章,上传图片: (4) 客户端2(lamp),挂载samba  server导出的文件系统至/var/www/html:验正其wordpress是否可被访问: 要

redis存储对象与对象序列化详解

redis主要存储类型最常用的五种数据类型: String Hash List Set Sorted set redis存储对象序列化和反序列化 首先来了解一下为什么要实现序列化 为什么要实现序列化接口 当一个类实现了Serializable接口(该接口仅为标记接口,不包含任何方法定义),表示该类可以序列化.序列化的目的是将一个实现了Serializable接口的对象转换成一个字节序列,可以. 把该字节序列保存起来(例如:保存在一个文件里),以后可以随时将该字节序列恢复为原来的对象.甚至可以将该

怎样在Redis通过StackExchange.Redis 存储集合类型List

StackExchange 是由StackOverFlow出品, 是对Redis的.NET封装,被越来越多的.NET开发者使用在项目中. 绝大部分原先使用ServiceStack的开发者逐渐都转了过来,由于SS在其新版中不再开源,并对免费版本有所限制. 实际问题 那么用.NET的开发者会发现,其根本没有对List类型的存储封装,那么要实现一个类似如下需求:假如我有一个Customer的模型. public class Customer { public string FirstName { ge

mysql 的存储引擎介绍

在数据库中存的就是一张张有着千丝万缕关系的表,所以表设计的好坏,将直接影响着整个数据库.而在设计表的时候,我们都会关注一个问题,使用什么存储引擎.等一下,存储引擎?什么是存储引擎? 什么是存储引擎? MySQL中的数据用各种不同的技术存储在文件(或者内存)中.这些技术中的每一种技术都使用不同的存储机制.索引技巧.锁定水平并且最终提供广泛的不同的功能和能力.通过选择不同的技术,你能够获得额外的速度或者功能,从而改善你的应用的整体功能. 例如,如果你在研究大量的临时数据,你也许需要使用内存MySQL