Java动态代理实现动态爬虫

Java动态代理实现动态爬虫笔者公司是一家区块链门户网站,该网站的很多资讯,快讯,视频等数据都是通过爬虫爬取得第三方网站获得的,需要从很多网站要爬取数据,如果每个数据源网站都需要单独写个接口去爬的话,工作量无疑是巨大的,因为笔者想到了通过动态代理实现一套爬虫机制,每次要爬取新的数据源,只要在数据库里增加一条数据源即可,无需修改代码。废话不多说,下贴出数据库表结构DROPTABLEIFEXISTS…

大家好,又见面了,我是你们的朋友全栈君。

笔者公司是一家区块链门户网站,该网站的很多资讯,快讯,视频等数据都是通过爬虫爬取得第三方网站获得的,需要从很多网站要爬取数据,如果每个数据源网站都需要单独写个接口去爬的话,工作量无疑是巨大的,因为笔者想到了通过动态代理实现一套爬虫机制,每次要爬取新的数据源,只要在数据库里增加一条数据源即可,无需修改代码。
废话不多说,下贴出数据库表结构

DROP TABLE IF EXISTS `yiyi_crawler_website`;
CREATE TABLE `yiyi_crawler_website` ( `id` bigint(16) NOT NULL AUTO_INCREMENT COMMENT '自增ID', `gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间', `url` varchar(255) DEFAULT NULL COMMENT '网站链接(抓取内容的接口)', `interval` bigint(16) DEFAULT '0' COMMENT '抓取时间间隔(以毫秒为单位)', `website_type` tinyint(20) DEFAULT NULL COMMENT '网站类型(1、快讯)', `website_name` varchar(32) DEFAULT NULL COMMENT '网站名', `source_link` varchar(255) DEFAULT NULL COMMENT '来源链接', `data_field` varchar(32) DEFAULT NULL COMMENT '数据所在字段,如果没有,为空则直接取数(多级以.连接,如果:data.items表示data下面的items为内容列表)', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
DROP TABLE IF EXISTS `yiyi_crawler_website_content`;
CREATE TABLE `yiyi_crawler_website_content` ( `id` bigint(16) NOT NULL AUTO_INCREMENT, `gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间', `website_id` bigint(16) DEFAULT NULL COMMENT '网站ID', `content_name` varchar(16) DEFAULT NULL COMMENT '内容名', `table_name` varchar(32) DEFAULT NULL COMMENT '所属表名', `column_name` varchar(32) DEFAULT NULL COMMENT '所属字段名', `return_field` varchar(32) DEFAULT NULL COMMENT '当前要抓取的字段所返回的字段', `field_type` tinyint(2) DEFAULT '2' COMMENT '字段类型(1、日期2、数值0、其他)', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

下面贴出爬虫的动态代理实现,基于cglib框架实现的

/** * 爬虫任务代理接口 * * @author liyi * @create 2018-03-17 16:58 **/
public interface CrawlerProxy { 
   

    /** * 任务开始 * @param website */
    void start(CrawlerWebsiteModelOut website);
}
/** * 爬虫任务类 * * @author liyi * @create 2018-03-17 18:21 **/
public class CrawlerTask implements CrawlerProxy { 
   

    @Override
    public void start(CrawlerWebsiteModelOut website) {
        System.out.println("爬虫任务开始");
    }
}
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.lynn.yiyi.http.Request;
import com.lynn.yiyi.http.WebUtils;
import com.lynn.yiyi.model.out.CrawlerWebsiteModelOut;

import java.util.*;

/** * 爬虫定时任务 * * @author liyi * @create 2018-03-17 18:35 **/
public class CrawlerTimerTask extends TimerTask { 
   
    private CrawlerWebsiteModelOut website = null;

    @Override
    public void run() {
        String json = WebUtils.executeHttp(Request.options().setMethod(com.lynn.yiyi.http.Method.GET).setUrl(website.getUrl()).build()).getJsonString();
        String strs[] = website.getDataField().split(".");
        List<String> dataList = new ArrayList<>();
        Arrays.stream(strs).forEach(s -> {
            dataList.clear();
            String data = JSON.parseObject(json, new TypeReference<Map<String, List<Map<String, String>>>>() {}.getType());
            dataList.add(data);
        });
    }

    public void setWebsite(CrawlerWebsiteModelOut website) {
        this.website = website;
    }

    public CrawlerWebsiteModelOut getWebsite() {
        return website;
    }
}
import com.alibaba.fastjson.JSONObject;
import com.lynn.yiyi.http.Request;
import com.lynn.yiyi.http.WebUtils;
import com.lynn.yiyi.model.out.CrawlerWebsiteModelOut;
import com.lynn.yiyi.service.CrawlerService;
import com.lynn.yiyi.utils.SpringUtils;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/** * 爬虫动态代理类 * * @author liyi * @create 2018-03-17 18:22 **/
public class CrawlerCglibProxy implements MethodInterceptor { 
   

    private Map<Long,Timer> timerMap = new HashMap<>();

    private Enhancer enhancer = new Enhancer();

    Object getProxy(Class<?> clazz){
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        Object o = proxy.invokeSuper(obj,args);
        if("start".equals(method.getName())){
            if(args[0] instanceof CrawlerWebsiteModelOut){
                CrawlerWebsiteModelOut website = (CrawlerWebsiteModelOut)args[0];
                if(timerMap.get(website.getId()) == null){
                    Timer timer = new Timer();
                    timer.schedule(new TimerTask() {
                        @Override
                        public void run() {
                            String data = WebUtils.executeHttp(Request.options().setMethod(com.lynn.yiyi.http.Method.GET).setUrl(website.getUrl()).build()).getJsonString();
                            String strs[] = website.getDataField().split("\\.");
                            for (String s : strs) {
                                JSONObject object = JSONObject.parseObject(data);
                                data = object.getString(s);
                            }
                            //TODO 这里将爬取到的数据写到数据库对应的表中
                        }
                    }, 0, website.getInterval());
                    timerMap.put(website.getId(),timer);
                }
            }
        }
        return o;
    }

    public static <T> T create(Class<T> cls){
        CrawlerCglibProxy proxy = new CrawlerCglibProxy();
        return (T)proxy.getProxy(cls);
    }

}
import java.util.ArrayList;
import java.util.List;

/** * 网站爬虫输出参数 * * @author liyi * @create 2018-03-17 17:04 **/
public class CrawlerWebsiteModelOut extends BaseModelOut { 
   

    private String url;

    private Long interval;

    private Integer websiteType;

    private String websiteName;

    private String sourceLink;

    private String dataField;

    private List<CrawlerWebsiteContentModelOut> contentList = new ArrayList<>();

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public Long getInterval() {
        return interval;
    }

    public void setInterval(Long interval) {
        this.interval = interval;
    }

    public Integer getWebsiteType() {
        return websiteType;
    }

    public void setWebsiteType(Integer websiteType) {
        this.websiteType = websiteType;
    }

    public String getWebsiteName() {
        return websiteName;
    }

    public void setWebsiteName(String websiteName) {
        this.websiteName = websiteName;
    }

    public String getSourceLink() {
        return sourceLink;
    }

    public void setSourceLink(String sourceLink) {
        this.sourceLink = sourceLink;
    }

    public String getDataField() {
        return dataField;
    }

    public void setDataField(String dataField) {
        this.dataField = dataField;
    }

    public List<CrawlerWebsiteContentModelOut> getContentList() {
        return contentList;
    }

    public void setContentList(List<CrawlerWebsiteContentModelOut> contentList) {
        this.contentList = contentList;
    }
}
/** * 爬虫网站内容输出参数 */
public class CrawlerWebsiteContentModelOut extends BaseModelOut{ 
   

    private Long websiteId;

    private String contentName;

    private String tableName;

    private String columnName;

    private String returnField;

    private Integer fieldType;

    public Long getWebsiteId() {
        return websiteId;
    }

    public void setWebsiteId(Long websiteId) {
        this.websiteId = websiteId;
    }

    public String getContentName() {
        return contentName;
    }

    public void setContentName(String contentName) {
        this.contentName = contentName;
    }

    public String getTableName() {
        return tableName;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName;
    }

    public String getColumnName() {
        return columnName;
    }

    public void setColumnName(String columnName) {
        this.columnName = columnName;
    }

    public String getReturnField() {
        return returnField;
    }

    public void setReturnField(String returnField) {
        this.returnField = returnField;
    }

    public Integer getFieldType() {
        return fieldType;
    }

    public void setFieldType(Integer fieldType) {
        this.fieldType = fieldType;
    }

}
import java.util.Date;
/** * 基础输出参数 * * @author liyi * @create 2018-03-17 17:02 **/
public abstract class BaseModelOut{ 
   

    private Long id;

    private Date create;

    private Date modified;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Date getCreate() {
        return create;
    }

    public void setCreate(Date create) {
        this.create = create;
    }

    public Date getModified() {
        return modified;
    }

    public void setModified(Date modified) {
        this.modified = modified;
    }
}

下面给出测试的main方法

public static void main(String[] args) {
        CrawlerProxy proxy = CrawlerFactory.create();
        proxy.start(website);//website即当前要爬取的网站对象,可以从数据库中读取
    }

调用了main方法即可启动定时器,定时从指定website爬取数据。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/159775.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 算法之记忆化搜索_艾宾浩斯记忆曲线的算法实现

    算法之记忆化搜索_艾宾浩斯记忆曲线的算法实现记忆化搜索其实就是暴力搜索的过程中保存一些已经计算过的状态(思想类似于动态规划,保存计算过的状态),在暴力搜索的过程中利用这些计算过的状态从而减少很大程度上的计算,从而达到时间复杂度上的优化。1【问题描述】 小明想知道,满足以下条件的正整数序列的数量: 1.第一项为n; 2.第二项不超过n; 3.从第三项开始,每一项小于前两项的差的绝对值。 请计算,对于给定的n,有多少种满足条件的序列。【输入格式】 输入一行包含一个整数n。【输出格式】 输出一个整数,表示答案。答案可能很大

    2022年9月1日
    4
  • mysql数据库备份方法_oracle数据库备份文件格式

    mysql数据库备份方法_oracle数据库备份文件格式数据库备份Mysqldump:逻辑备份,热备份,全量xtrabackup:物理,热,全量+增量备份一、什么是MySQL主备情况一:客户端的业务操作,读、写访问的是主库主库通过某种机制,将数据实时同步给备库主库由于有些原因,无法正常响应客户端的请求情况二:完成主备切换客户端读写,访问的是备库(此时备库升级为新主库)数据同步是如何实现的?1.主从同步原理1、在备库执行changemaster命令,绑定主库的信息mysql>CHANGEMAS

    2025年5月25日
    1
  • 备忘录模式实例_iphone语音备忘录无法分享

    备忘录模式实例_iphone语音备忘录无法分享备忘录模式 Motivation动机模式定义实例结构要点总结笔记动机在软件构建过程中,某些对象的状态在转换过程中,可能由于某种需要,要求程序能够回溯对象之前处于某个点时的状态.如果使用一些共有接口来让其他对象得到对象的状态,便会暴露对象的实现细节.如何实现对象状态的良好保存与回复?但同时又不会因此而破坏对象的封装性模式定义在不破坏封装性的前提下.捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可以将该对象恢复到原先保存的状态实例朴素class Memento{ stri

    2022年8月9日
    7
  • pycharm专业版安装与激活方法

    pycharm专业版安装与激活方法1、首先下载pycharm专业版:点击打开链接;2、激活成功教程教程:下载激活成功教程补丁和注册码如果仍未激活。参考:https://blog.csdn.net/qq_32811489/article/details/78636049注:激活成功教程补丁跟注册码一直在更新,文…

    2022年8月28日
    2
  • python基础语法个人笔记_python语法规则

    python基础语法个人笔记_python语法规则python语法规范python的语法规范非常重要,简洁明了是python的特性,以下是python语法的一些说明python3的编码格式是unicode(utf-8)标识符的规则:由字母、数字

    2022年7月31日
    6
  • 解决docker下载镜像速度过慢_docker拉取镜像失败

    解决docker下载镜像速度过慢_docker拉取镜像失败前言上一篇讲到pull镜像,但是pull镜像的时候下拉的速度实在感人,有什么解决办法吗?我们只需将docker镜像源修改为国内的将docker镜像源修改为国内的:在/etc/docker/d

    2022年7月31日
    8

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号