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

网友投稿 254 2023-02-20


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

今年十月份以来,跟朋友尝试导入一些图片到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:

com.cv4j.piccrawler

crawler

0.2.1

pom

二.使用方法:

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次。

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 StriHAJPNpfng picFormat() {

return "png";

}

@Override

public FileGenType genType() {

return FileGenType.AUTOhttp://_INCREMENT;

}

})

.repeat(200)

.build()

.downloadPicToFlowable(url)

.subscribe(new Consumer() {

@Override

public void accept(File file) throws Exception {

// do something

}

});

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

2.2 下载多张图片

List 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://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);

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

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

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

urls.add("http://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的全部图片。

/**

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

* @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 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 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 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 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 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实现的。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:微信小程序 如何引入外部字体库iconfont的图标
下一篇:微信接口开发 java(微信接口开发课程要学哪些东西)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~