首页 > 系统 > Android > 正文

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

2019-10-22 18:15:50
字体:
来源:转载
供稿:网友

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

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

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

一.下载安装:

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

repositories {  mavenCentral()  jcenter()}

Gradle:

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

Maven:

<dependency> <groupId>com.cv4j.piccrawler</groupId> <artifactId>crawler</artifactId> <version>0.2.1</version> <type>pom</type></dependency>

二.使用方法:

2.1 下载单张图片

1、普通方式

    String url = "..."; // 图片的地址    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) // 重复200次        .build()        .downloadPic(url);

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

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

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

RxJava2,图片爬虫,简单爬虫,简单爬虫图片

2、使用RxJava的方式下载

    String url = "..."; // 图片的地址    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()        .downloadPicUseRx(url);

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

    String url = "..."; // 图片的地址    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 下载多张图片

    List<String> urls = ...; // 多张图片地址的集合    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()        .downloadPics(urls);

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

    String url = "http://www.jianshu.com/u/4f2c483c12d8"; // 针对某一网址    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(url);

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

RxJava2,图片爬虫,简单爬虫,简单爬虫图片

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

 

    List<String> urls = new ArrayList<>(); // 多个网页的集合    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);

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

RxJava2,图片爬虫,简单爬虫,简单爬虫图片

三. 部分源码解析

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

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

  /**   * 下载整个网页的全部图片   * @param url   */  public void downloadWebPageImages(String url) {    Flowable.just(url)        .map(s->httpManager.createHttpWithGet(s))        .map(response->parseHtmlToImages(response))        .subscribe(urls -> downloadPics(urls),            throwable-> System.out.println(throwable.getMessage()));  }

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

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

  public CloseableHttpResponse createHttpWithGet(String url) {    // 获取客户端连接对象    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的操作方法来取出和操作数据。

private List<String> parseHtmlToImages(CloseableHttpResponse response) {    // 获取响应实体    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。

  /**   * 下载多张图片   * @param urls   */  public void downloadPics(List<String> urls) {    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集合,表示多个网页的地址。

  /**   * 下载多个网页的全部图片   * @param urls   */  public void downloadWebPageImages(List<String> urls) {    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 是一个简单的图片爬虫,目前基本可以满足我的需求。未来要是有新的需求,我会不断添加功能。

在做PicCrawler时,其实还做了一个ProxyPool用于获取可用代理池的库,它也是基于RxJava2实现的。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持VEVB武林网。


注:相关教程知识阅读请移步到Android开发频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表