基于RxJava2实现的简单图片爬虫

本文介绍了一款基于Java的简易图片爬虫PicCrawler的设计与实现。该爬虫支持单张或多张图片下载、网页图片抓取等功能,并利用HttpClient、RxJava2及Java8特性实现高效稳定的数据抓取。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今年十月份以来,跟朋友尝试导入一些图片到tensorflow来生成模型,这就需要大量的图片。刚开始我只写了一个简单的HttpClient程序来抓取图片,后来为了通用性索性写一个简单的图片爬虫程序。它可以用于抓取单张图片、多张图片、某个网页下的所有图片、多个网页下的所有图片。

github地址:https://github.com/fengzhizi715/PicCrawler

这个爬虫使用了HttpCient、RxJava2以及Java 8的一些特性。它支持一些简单的定制,比如定制User-Agent、Referer、Cookies等。

一.下载安装:

对于Java项目如果使用gradle构建,由于默认不是使用jcenter,需要在相应module的build.gradle中配置

  1. repositories {

  2.    mavenCentral()

  3.    jcenter()

  4. }

Gradle:

  1. compile 'com.cv4j.piccrawler:crawler:0.2.1'

Maven:

  1. <dependency>

  2.  <groupId>com.cv4j.piccrawler</groupId>

  3.  <artifactId>crawler</artifactId>

  4.  <version>0.2.1</version>

  5.  <type>pom</type>

  6. </dependency>

二.使用方法:

2.1 下载单张图片

  1. 普通方式

  1.        String url = "..."; // 图片的地址

  2.        CrawlerClient.get()

  3.                .timeOut(6000)

  4.                .fileStrategy(new FileStrategy() {

  5.                    @Override

    •                    public String filePath() {

    •                        return "temp";

    •                    }

    •                    @Override

      •                    public String picFormat() {

      •                        return "png";

      •                    }

      •                    @Override

        •                    public FileGenType genType() {

        •                        return FileGenType.AUTO_INCREMENT;

          •                    }

          •                })

          •                .repeat(200) // 重复200次

          •                .build()

          •                .downloadPic(url);

在这里,timeOut()表示网络请求的超时时间。fileStrategy()表示存放的目录、文件使用的格式、生成的文件时使用何种策略。repeat()表示对该图片请求重复的次数。

PicCrawler支持多种文件的生成策略,比如随机生成文件名、从1开始自增长地生成文件名、生成指定的文件名等等。

下图显示了使用该程序对某验证码的图片下载200次。


2. 使用RxJava的方式下载

  1.        String url = "..."; // 图片的地址

  2.        CrawlerClient.get()

  3.                .timeOut(6000)

  4.                .fileStrategy(new FileStrategy() {

  5.                    @Override

    •                    public String filePath() {

    •                        return "temp";

    •                    }

    •                    @Override

      •                    public String picFormat() {

      •                        return "png";

      •                    }

      •                    @Override

        •                    public FileGenType genType() {

        •                        return FileGenType.AUTO_INCREMENT;

          •                    }

          •                })

          •                .repeat(200)

          •                .build()

          •                .downloadPicUseRx(url);


3. 使用RxJava,下载之后的图片还能做后续的处理

  1.        String url = "..."; // 图片的地址

  2.        CrawlerClient.get()

    •                .timeOut(6000)

    •                .fileStrategy(new FileStrategy() {

    •                    @Override

      •                    public String filePath() {

      •                        return "temp";

      •                    }

      •                    @Override

        •                    public String picFormat() {

        •                        return "png";

        •                    }

        •                    @Override

          •                    public FileGenType genType() {

          •                        return FileGenType.AUTO_INCREMENT;

            •                    }

            •                })

            •                .repeat(200)

            •                .build()

            •                .downloadPicToFlowable(url)

            •                .subscribe(new Consumer<File>() {

            •                    @Override

            •                    public void accept(File file) throws Exception {

            •                        // do something

            •                    }

            •                });

在Consumer中,可以对文件做一些后续的处理。

2.2 下载多张图片

  1.        List<String> urls = ...; // 多张图片地址的集合

  2.        CrawlerClient.get()

  3.                .timeOut(6000)

  4.                .fileStrategy(new FileStrategy() {

  5.                    @Override

    •                    public String filePath() {

    •                        return "temp";

    •                    }

    •                    @Override

      •                    public String picFormat() {

      •                        return "png";

      •                    }

      •                    @Override

        •                    public FileGenType genType() {

        •                        return FileGenType.AUTO_INCREMENT;

          •                    }

          •                })

          •                .build()

          •                .downloadPics(urls);

2.3 下载某个网页的全部图片

  1.        String url = "http://www.jianshu.com/u/4f2c483c12d8"; // 针对某一网址

  2.        CrawlerClient.get()

  3.                .timeOut(6000)

  4.                .fileStrategy(new FileStrategy() {

  5.                    @Override

    •                    public String filePath() {

    •                        return "temp";

    •                    }

    •                    @Override

      •                    public String picFormat() {

      •                        return "png";

      •                    }

      •                    @Override

        •                    public FileGenType genType() {

        •                        return FileGenType.AUTO_INCREMENT;

          •                    }

          •                })

          •                .build()

          •                .downloadWebPageImages(url);

使用上面的程序,对我简书主页上的图片进行抓取。


2.4 下载多个网页的全部图片

  1.        List<String> urls = new ArrayList<>(); // 多个网页的集合

  2.        urls.add("http://www.jianshu.com/u/4f2c483c12d8");

    •        urls.add("https://toutiao.io/");

    •        CrawlerClient.get()

      •                .timeOut(6000)

      •                .fileStrategy(new FileStrategy() {

      •                    @Override

        •                    public String filePath() {

        •                        return "temp";

        •                    }

        •                    @Override

          •                    public String picFormat() {

          •                        return "png";

          •                    }

          •                    @Override

            •                    public FileGenType genType() {

            •                        return FileGenType.AUTO_INCREMENT;

              •                    }

              •                })

              •                .build()

              •                .downloadWebPageImages(urls);

下载个人简书主页上的图以及开发者头条的图片。


三. 部分源码解析

3.1 下载某个网页的全部图片

downloadWebPageImages()方法表示下载某个url的全部图片。

  1.    /**

  2.     * 下载整个网页的全部图片

  3.     * @param url

  4.     */

  5.    public void downloadWebPageImages(String url) {

  6.        Flowable.just(url)

    •                .map(s->httpManager.createHttpWithGet(s))

    •                .map(response->parseHtmlToImages(response))

    •                .subscribe(urls -> downloadPics(urls),

    •                        throwable-> System.out.println(throwable.getMessage()));

    •    }

downloadWebPageImages()分成三步:创建网络请求、解析出当前页面中包含的图片路径、下载这些图片。

第一步,创建网络请求使用了HttpClient。

  1.    public CloseableHttpResponse createHttpWithGet(String url) {

  2.        // 获取客户端连接对象

    •        CloseableHttpClient httpClient = getHttpClient();

    •        // 创建Get请求对象

    •        HttpGet httpGet = new HttpGet(url);

    •        if (Preconditions.isNotBlank(httpParam)) {

      •            Map<String,String> header = httpParam.getHeader();

        •            if (Preconditions.isNotBlank(header)) {

          •                for (String key : header.keySet()) {

          •                    httpGet.setHeader(key,header.get(key));

          •                }

          •            }

          •        }

          •        CloseableHttpResponse response = null;

            •        // 执行请求

              •        try {

              •            response = httpClient.execute(httpGet);

              •        } catch (IOException e) {

              •            e.printStackTrace();

              •        }

              •        return response;

                •    }

第二步,将返回的response转换成String类型,使用jsoup将带有图片的链接全部过滤出来。

jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。

  1. private List<String> parseHtmlToImages(CloseableHttpResponse response) {

  2.        // 获取响应实体

    •        HttpEntity entity = response.getEntity();

    •        InputStream is = null;

      •        String html = null;

      •        try {

        •            is = entity.getContent();

        •            html = IOUtils.inputStream2String(is);

        •        } catch (IOException e) {

        •            e.printStackTrace();

        •        }

        •        Document doc = Jsoup.parse(html);

          •        Elements media = doc.select("[src]");

            •        List<String> urls = new ArrayList<>();

            •        if (Preconditions.isNotBlank(media)) {

              •            for (Element src : media) {

                •                if (src.tagName().equals("img")) {

                •                    if (Preconditions.isNotBlank(src.attr("abs:src"))) { // 图片的绝对路径不为空

                  •                        String picUrl = src.attr("abs:src");

                    •                        log.info(picUrl);

                    •                        urls.add(picUrl);

                    •                    } else if (Preconditions.isNotBlank(src.attr("src"))){ // 图片的相对路径不为空

                    •                        String picUrl = src.attr("src").replace("//","");

                      •                        picUrl = "http://"+Utils.tryToEscapeUrl(picUrl);

                      •                        log.info(picUrl);

                      •                        urls.add(picUrl);

                      •                    }

                      •                }

                      •            }

                      •        }

                      •        if (response != null) {

                        •            try {

                        •                EntityUtils.consume(response.getEntity());

                        •                response.close();

                        •            } catch (IOException e) {

                        •                System.err.println("释放链接错误");

                        •                e.printStackTrace();

                        •            }

                        •        }

                        •        return urls;

                          •    }

第三步,下载这些图片使用了Java 8的CompletableFuture。CompletableFuture是Java 8新增的用于异步处理的类,而且CompletableFuture的性能也好于传统的Future。

  1.    /**

  2.     * 下载多张图片

  3.     * @param urls

  4.     */

  5.    public void downloadPics(List<String> urls) {

  6.        if (Preconditions.isNotBlank(urls)) {

    •            urls.stream().parallel().forEach(url->{

    •                try {

      •                    CompletableFuture.runAsync(() -> downloadPic(url)).get();

      •                } catch (InterruptedException e) {

      •                    e.printStackTrace();

      •                } catch (ExecutionException e) {

      •                    e.printStackTrace();

      •                }

      •            });

      •        }

      •    }

3.2 下载多个网页的全部图片

downloadWebPageImages()方法还支持传List集合,表示多个网页的地址。

  1.    /**

  2.     * 下载多个网页的全部图片

  3.     * @param urls

  4.     */

  5.    public void downloadWebPageImages(List<String> urls) {

  6.        if (Preconditions.isNotBlank(urls)) {

    •            Flowable.fromIterable(urls)

      •                    .parallel()

      •                    .map(url->httpManager.createHttpWithGet(url))

      •                    .map(response->parseHtmlToImages(response))

      •                    .sequential()

      •                    .subscribe(list -> downloadPics(list),

      •                            throwable-> System.out.println(throwable.getMessage()));

      •        }

      •    }

在这里其实用到了ParallelFlowable,因为parallel()可以把Flowable转成ParallelFlowable。

总结

PicCrawler(https://github.com/fengzhizi715/PicCrawler) 是一个简单的图片爬虫,目前基本可以满足我的需求。未来要是有新的需求,我会不断添加功能。

在做PicCrawler时,其实还做了一个ProxyPool(https://github.com/fengzhizi715/ProxyPool)用于获取可用代理池的库,它也是基于RxJava2实现的。

关注【Java与Android技术栈】

更多精彩内容请关注扫码


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值