1.简介

AiPa 是一款小巧,灵活,扩展性高的多线程爬虫框架。

AiPa 依赖当下最简单的HTML解析器Jsoup。

AiPa 只需要使用者提供网址集合,即可在多线程下自动爬取,并对一些异常进行处理。

2.Maven

直接引入

<dependency>
    <groupId>cn.yueshutong</groupId>
    <artifactId>AiPa</artifactId>
    <version>1.0.0.RELEASE</version>
</dependency>

3.如何使用

先来看下一个简单完整的示例程序:

必须实现的接口

public class MyAiPaWorker implements AiPaWorker {

    @Override
    public String run(Document doc, AiPaUtil util) {
        //使用JSOUP进行HTML解析获取想要的div节点和属性
        //保存在数据库或本地文件中
        //新增aiPaUtil工具类可以再次请求网址
        return doc.title() + doc.body().text();
    }

    @Override
    public Boolean fail(String link) {
        //任务执行失败
        //可以记录失败网址
        //记录日志
        return false;
    }
}

main方法

    public static void main(String[] args) throws InstantiationException, IllegalAccessException, ExecutionException, InterruptedException {
        //准备网址集合
        List<String> linkList = new ArrayList<>();
        linkList.add("http://jb39.com/jibing/FeiQiZhong265988.htm");
        linkList.add("http://jb39.com/jibing/XiaoErGuoDu262953.htm");
        linkList.add("http://jb39.com/jibing/XinShengErShiFei250995.htm");
        linkList.add("http://jb39.com/jibing/GaoYuanFeiShuiZhong260310.htm");
        linkList.add("http://jb39.com/zhengzhuang/LuoYin337449.htm");
        //第一步:新建AiPa实例
        AiPaExecutor aiPaExecutor = AiPa.newInstance(new MyAiPaWorker()).setCharset(Charset.forName("GBK"));
        //第二步:提交任务
        for (int i = 0; i < 10; i++) {
            aiPaExecutor.submit(linkList);
        }
        //第三步:读取返回值
        List<Future> futureList = aiPaExecutor.getFutureList();
        for (int i = 0; i < futureList.size(); i++) {
            //get() 方法会阻塞当前线程直到获取返回值
            System.out.println(futureList.get(i).get());
        }
        //第四步:关闭线程池
        aiPaExecutor.shutdown();
    }

通过AiPa.newInstance()方法直接创建一个新的AiPa实例,该方法必须要传入 AiPaWorker 接口的实现类。

3.1 AiPaWorker接口

AiPaWorker 接口是用户必须要实现的业务类。

该接口方法如下:

public interface AiPaWorker<T,S> {
    /**
     * 如何解析爬下来的HTML文档?
     * @param doc JSOUP提供的文档
     * @param util 爬虫工具类
     * @return
     */
    T run(Document doc, AiPaUtil util);

    /**
     * run方法异常则执行fail方法
     * @param link 网址
     * @return
     */
    S fail(String link);
}

run()方法是用户自定义处理爬取的HTML内容,一般是利用Jsoup的Document类进行解析,获取节点或属性等,然后保存到数据库或本地文件中。如果在业务方法需要再次请求URL,可以使用工具类Util。

fail()方法是当run()方法出现异常或爬取网页时异常,多次处理无效的情况下进入的方法,该方法的参数为此次出错的网址。一般是对其进行日志记录等操作。

3.2 解码,最多失败次数,请求头

通过AiPa获取实例后,可以直接在后面跟着设置一大堆属性,比如:setCharset、setThreads、setMaxFailCount等,这些属性啥意思,下面以表格的形式说明一下:

方法 说明
setThreads 工作线程数,默认CPU数量+1,你也可以设置CPU*2等等
setMaxFailCount 最大失败次数,也就是爬网站出现异常,再次爬一共尝试多少次,默认5
setCharset 网页的编码,碰到乱码设置这个,默认UTF-8
setHeader 设置请求头,只接受Map<String,String>类型,默认null
setMethod 设置请求方法,默认Method.GET
setTimeout 请求解析的等待时间,默认30秒。
setUserAgent 设置请求的UA,默认电脑版。

上面的一般情况下够用了,如果对这些不满意,嫌太少啥的,下面给了更优秀的解决方案。

3.3 自定义爬虫类

在上面的演示程序中,我们使用了submit()方法进行提交任务,默认是使用了Jsoup+上面的那些非加粗属性进行爬取,一般情况下够用,如果要一个一个的扩展Jsoup的方法太累了,于是我想到把爬虫方法提供给用户重,让用户自己去扩展,想用什么爬,想设置什么属性都可以。

下面看下使用Demo:

public class MyAiPaUtil extends AiPaUtil {

    @Override
    public Document getHtmlDocument(String link) throws IOException {
        // 你可以不用JSOUP,可以使用其它方法进行HTTP请求,但最后需要转为Document格式
        // 你也可以使用Jsoup实现定制属性
        Connection connection = Jsoup.connect(link).method(Connection.Method.GET);
        String body = connection.execute().charset("GBK").body();

        return Jsoup.parse(body);
    }

}

然后,再调用submit方法提交任务,代码示例:

aiPaExecutor.submit(linkList, MyAiPaUtil.class);

注意:当你重写爬虫方法后,3.2小节的非加粗属性都会失效。

3.3 读取返回值与获取线程池

如果你想要读取返回值来看下任务是否执行成功,你可以使用看下上面的程示例序是如何做的。

public List<Future> getFutureList()

getFutureList()方法会返回任务执行之后的结果集合,集合中的成员都是Future类。调用Future对象的 get() 方法会等待当前任务执行完成再返回结果值,也就是会阻塞当前线程。该类还有很多方法,比如get(long timeout, TimeUnit unit),设置等待时间等等。

public ExecutorService getExecutor()

该方法会返回AiPa当前使用的Executor线程池,你获取到该线程池后,需要一些使用线程池的一些方法可以自行使用。

3.4 如何应对爬取网页时的异常

对于网页爬取时的异常,这真的是个痛点。原因真的很多,你的网络不行,网站服务器的网络不行,在网上有说把请求头中Connection设置为close,不用keep-alive。这个以我爬取几百兆数据的经验告诉你,然并卵。

于是我想出了一种无赖打法,反复爬。爬一次不行就两次,爬两次不行就三次,只要网页是可以正常响应的,基本这个策略没多少问题。当然,万一真的是某个网页就那么独树一帜呢,所以我们设置一个最大值,对于爬取超过最大值的,放弃记录下来,看看啥子情况。在我的这个框架中,也给出了fail()方法专门处理这个问题。

4.测试用例

在Java SE测试中。没有使用数据库等,直接控制台打印是没问题的。

在Spring Boot中写了个测试用例,爬取数据保存到数据库,运行也没问题。

@RunWith(SpringRunner.class)
@SpringBootTest
public class InterApplicationTests {

    @Autowired
    private DemoResponse demoResponse;

    @Test
    public void context() throws ExecutionException, InterruptedException {
        AiPaExecutor executor = AiPa.newInstance(new AiPaWorker() {
            @Override
            public Boolean run(Document document, AiPaUtil util) {
                String title = document.title();
                demoResponse.save(new DemoEntity(title));
                return true;
            }

            @Override
            public Boolean fail(String s) {
                demoResponse.save(new DemoEntity(s));
                return false;
            }
        }).setCharset(Charset.forName("GBK"));

        List<String> linkList = new ArrayList<>();
        linkList.add("http://jb39.com/jibing/FeiQiZhong265988.htm");
        linkList.add("http://jb39.com/jibing/XiaoErGuoDu262953.htm");
        linkList.add("http://jb39.com/jibing/XinShengErShiFei250995.htm");
        linkList.add("http://jb39.com/jibing/GaoYuanFeiShuiZhong260310.htm");
        linkList.add("http://jb39.com/zhengzhuang/LuoYin337449.htm");
        executor.submit(linkList);

        List<Future> list = executor.getFutureList();
        for (int i = 0; i < list.size(); i++) {
            //get() 方法会阻塞当前线程直到获取返回值
            System.out.println(list.get(i).get());
        }
        executor.shutdown();
    }

}

运行结果:

Hibernate: insert into demo (title) values (?)
Hibernate: insert into demo (title) values (?)
Hibernate: insert into demo (title) values (?)
Hibernate: insert into demo (title) values (?)
Hibernate: insert into demo (title) values (?)

5.关于作者

由于作者水平有限,框架一定存在一些漏洞或不足,希望各位专家、大佬提出批评指正!

我的博客:https://yueshutong.cnblogs.com/

Github:https://github.com/yueshutong/AIPa

Giree:https://gitee.com/zyzpp/AIPa

交流QQ群:781927207

[原创]一款小巧、灵活的Java多线程爬虫框架(AiPa)的更多相关文章

  1. Java 多线程爬虫及分布式爬虫架构探索

    这是 Java 爬虫系列博文的第五篇,在上一篇 Java 爬虫服务器被屏蔽,不要慌,咱们换一台服务器 中,我们简单的聊反爬虫策略和反反爬虫方法,主要针对的是 IP 被封及其对应办法.前面几篇文章我们把 ...

  2. Java 多线程爬虫及分布式爬虫架构

    这是 Java 爬虫系列博文的第五篇,在上一篇 Java 爬虫服务器被屏蔽,不要慌,咱们换一台服务器 中,我们简单的聊反爬虫策略和反反爬虫方法,主要针对的是 IP 被封及其对应办法.前面几篇文章我们把 ...

  3. Java开源爬虫框架crawler4j

    花了两个小时把Java开源爬虫框架crawler4j文档翻译了一下,因为这几天一直在学习Java爬虫方面的知识,今天上课时突然感觉全英文可能会阻碍很多人学习的动力,刚好自己又正在接触这个爬虫框架,所以 ...

  4. [原创]一款基于Reactor线程模型的java网络爬虫框架

    AJSprider 概述 AJSprider是笔者基于Reactor线程模式+Jsoup+HttpClient封装的一款轻量级java多线程网络爬虫框架,简单上手,小白也能玩爬虫, 使用本框架,只需要 ...

  5. 介绍一款能取代 Scrapy 的 Python 爬虫框架 - feapder

    1. 前言 大家好,我是安果! 众所周知,Python 最流行的爬虫框架是 Scrapy,它主要用于爬取网站结构性数据 今天推荐一款更加简单.轻量级,且功能强大的爬虫框架:feapder 项目地址: ...

  6. Java多线程——AQS框架源码阅读

    AQS,全称AbstractQueuedSynchronizer,是Concurrent包锁的核心,没有AQS就没有Java的Concurrent包.它到底是个什么,我们来看看源码的第一段注解是怎么说 ...

  7. Java爬虫框架 | 爬小说

    Jsoup,Java爬虫解决方案,中文文档:jsoup   不得不说Java的生态真的好,原来我以为爬虫是只能用Pyhton来写的,结果发现Java的爬虫框架不要太多……       一分钟你就可以写 ...

  8. 学 Java 网络爬虫,需要哪些基础知识?

    说起网络爬虫,大家想起的估计都是 Python ,诚然爬虫已经是 Python 的代名词之一,相比 Java 来说就要逊色不少.有不少人都不知道 Java 可以做网络爬虫,其实 Java 也能做网络爬 ...

  9. JAVA开源爬虫列表及简介

    本文列举了一些较为常用的JAVA开源爬虫框架: 1.Apache Nutch 官方网站:http://nutch.apache.org/ 是否支持分布式:是 可扩展性:中.Apache Nutch并不 ...

随机推荐

  1. Python算法练习--把搜索树转成双向链表

    本文目前分享的题目都是来自于July的分享,然后把具体算法实现.搜索树转双向链表主要的实现逻辑是在中序遍历时,调整节点的左右子树:因为中序遍历是递归调用,所以在调整时一定要注意调整的位置,如果写错了, ...

  2. 【工具篇】Sublime Text 2 安装汉化破解、插件包安装教程详解

    Sublime Text概述: Sublime Text是一个代码编辑器,也是HTML和散文先进的文本编辑器. 漂亮的用户界面和非凡的功能,例如:迷你地图,多选择,Python插件,代码段等等. 完全 ...

  3. 实战经验|大神战队都在i春秋教你打CTF

    全国大学生信息安全竞赛创新实践能力赛旨在培养.选拔.推荐优秀信息安全专业人才创造条件,促进高等学校信息安全专业课程体系.教学内容和方法的改革,培养学生的创新意识与团队合作精神,普及信息安全知识,增强学 ...

  4. 从零开始学习PYTHON3讲义(十二)画一颗心送给你

    (内容需要,本讲使用了大量在线公式,如果因为转帖网站不支持公式无法显示的情况,欢迎访问原始博客.) <从零开始PYTHON3>第十二讲 上一节课我们主要讲解了数值计算和符号计算.数值计算的 ...

  5. 【Android Studio安装部署系列】二、Android Studio开发环境搭建

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 概述 Android Studio开发环境安装步骤 下载Android Studio 下载地址: http://www.wanandroi ...

  6. 【Android Studio安装部署系列】十九、Android studio使用SVN

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 概述 在AndroidStudio中开发版本控制,除了Git就是SVN,和Eclipse不同,Android Studio没有提供单独的插 ...

  7. KeyboardUtil【软键盘弹出后输入框上移一定的高度】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 演示获取软键盘高度并保存,然后根据输入框的原有位置是否被软键盘挡住了,如果被挡住了则将整体页面上移一定的高度,当软键盘隐藏的时候再下 ...

  8. ViewPagerWithImageDemo【ViewPager如何判断滑动到第一页和最后一页以及弹出对话框功能】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 记录viewpager滑动的时候弹出对话框的功能(关键功能是滑动弹出对话框后,隐藏对话框的时候当前页可以还原到原位置),顺便判断首页 ...

  9. springboot~JPA把ORM统一起来

    JPA介绍 JPA(Java Persistence API)是Sun官方提出的Java持久化规范.它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据.他的出现主要是为了简 ...

  10. 一个用来爬小说的简单的Node.js爬虫

    小说就准备点天下霸唱和南派三叔的系列,本人喜欢看,而且数据也好爬.貌似因为树大招风的原因,这两作者的的书被盗版的很多,乱改的也多.然后作者就直接在网上开放免费阅读了,还提供了官网,猜想作者应该是允许爬 ...