基于RxJava2實現(xiàn)的簡單圖片爬蟲的方法
今年十月份以來,跟朋友嘗試導(dǎo)入一些圖片到tensorflow來生成模型,這就需要大量的圖片。剛開始我只寫了一個簡單的HttpClient程序來抓取圖片,后來為了通用性索性寫一個簡單的圖片爬蟲程序。它可以用于抓取單張圖片、多張圖片、某個網(wǎng)頁下的所有圖片、多個網(wǎng)頁下的所有圖片。
github地址:https://github.com/fengzhizi715/PicCrawler
這個爬蟲使用了HttpClient、RxJava2以及Java 8的一些特性。它支持一些簡單的定制,比如定制User-Agent、Referer、Cookies等。
一.下載安裝:
對于Java項目如果使用gradle構(gòu)建,由于默認(rèn)不是使用jcenter,需要在相應(yīng)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) // 重復(fù)200次
.build()
.downloadPic(url);
在這里,timeOut()表示網(wǎng)絡(luò)請求的超時時間。fileStrategy()表示存放的目錄、文件使用的格式、生成的文件時使用何種策略。repeat()表示對該圖片請求重復(fù)的次數(shù)。
PicCrawler支持多種文件的生成策略,比如隨機生成文件名、從1開始自增長地生成文件名、生成指定的文件名等等。
下圖顯示了使用該程序?qū)δ瞅炞C碼的圖片下載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,下載之后的圖片還能做后續(xù)的處理
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中,可以對文件做一些后續(xù)的處理。
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 下載某個網(wǎng)頁的全部圖片
String url = "http://www.jianshu.com/u/4f2c483c12d8"; // 針對某一網(wǎng)址
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 下載多個網(wǎng)頁的全部圖片
List<String> urls = new ArrayList<>(); // 多個網(wǎng)頁的集合
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);
下載個人簡書主頁上的圖以及開發(fā)者頭條的圖片。

三. 部分源碼解析
3.1 下載某個網(wǎng)頁的全部圖片
downloadWebPageImages()方法表示下載某個url的全部圖片。
/**
* 下載整個網(wǎng)頁的全部圖片
* @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()分成三步:創(chuàng)建網(wǎng)絡(luò)請求、解析出當(dāng)前頁面中包含的圖片路徑、下載這些圖片。
第一步,創(chuàng)建網(wǎng)絡(luò)請求使用了HttpClient。
public CloseableHttpResponse createHttpWithGet(String url) {
// 獲取客戶端連接對象
CloseableHttpClient httpClient = getHttpClient();
// 創(chuàng)建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;
// 執(zhí)行請求
try {
response = httpClient.execute(httpGet);
} catch (IOException e) {
e.printStackTrace();
}
return response;
}
第二步,將返回的response轉(zhuǎn)換成String類型,使用jsoup將帶有圖片的鏈接全部過濾出來。
jsoup 是一款Java 的HTML解析器,可直接解析某個URL地址、HTML文本內(nèi)容。它提供了一套非常省力的API,可通過DOM,CSS以及類似于jQuery的操作方法來取出和操作數(shù)據(jù)。
private List<String> parseHtmlToImages(CloseableHttpResponse response) {
// 獲取響應(yīng)實體
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("http://","");
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的性能也好于傳統(tǒng)的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 下載多個網(wǎng)頁的全部圖片
downloadWebPageImages()方法還支持傳List集合,表示多個網(wǎng)頁的地址。
/**
* 下載多個網(wǎng)頁的全部圖片
* @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轉(zhuǎn)成ParallelFlowable。
總結(jié)
PicCrawler 是一個簡單的圖片爬蟲,目前基本可以滿足我的需求。未來要是有新的需求,我會不斷添加功能。
在做PicCrawler時,其實還做了一個ProxyPool用于獲取可用代理池的庫,它也是基于RxJava2實現(xiàn)的。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- RxJava2.x實現(xiàn)定時器的實例代碼
- 詳解RxJava2 Retrofit2 網(wǎng)絡(luò)框架簡潔輕便封裝
- RxJava2.x+ReTrofit2.x多線程下載文件的示例代碼
- Android 使用 RxJava2 實現(xiàn)倒計時功能的示例代碼
- 基于Retrofit2+RxJava2實現(xiàn)Android App自動更新
- RxJava2配置及使用詳解
- Android 用RxBinding與RxJava2實現(xiàn)短信驗證碼倒計時功能
- RxJava2和Retrofit2封裝教程(整潔、簡單、實用)
- Rxjava2_Flowable_Sqlite_Android數(shù)據(jù)庫訪問實例
- 談?wù)凴xJava2中的異常及處理方法
相關(guān)文章
Android WebView的使用方法及與JS 相互調(diào)用
這篇文章主要介紹了Android WebView的使用方法及與JS 相互調(diào)用的相關(guān)資料,WebView 是 Android 中一個非常實用的組​件, WebView 可以使得網(wǎng)頁輕松的內(nèi)嵌到app里,還可以直接跟js相互調(diào)用,需要的朋友可以參考下2017-07-07
Android學(xué)習(xí)之介紹Binder的簡單使用
BInder方面的資料雖然感覺看的比較多,但是真正用的時候才發(fā)現(xiàn)有很多地方模棱兩棵的,所以,打算用一個實例再來鞏固一下binder的使用方法。這篇文章主要介紹了Android中Binder的簡單使用,文中給出詳細(xì)的示例代碼,需要的朋友可以參考下2016-12-12
Android實現(xiàn)隨意拖動View效果的實例代碼
這篇文章主要介紹了Android實現(xiàn)隨意拖動View效果,本文通過實例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-07-07
Android Socket接口實現(xiàn)即時通訊實例代碼
這篇文章主要介紹了Android Socket接口實現(xiàn)即時通訊實例代碼的相關(guān)資料,這里對通訊知識進行了詳細(xì)介紹,并用Socket 接口實現(xiàn)通訊實例,需要的朋友可以參考下2016-12-12
Android實現(xiàn)數(shù)據(jù)按照時間排序
這篇文章主要為大家詳細(xì)介紹了Android實現(xiàn)數(shù)據(jù)按照時間排序的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-09-09
android 字體顏色選擇器(ColorPicker)介紹
本文將詳細(xì)介紹android 字體顏色選擇器(ColorPicker)需要了解更多的朋友可以參考下2012-11-11
Android Studio finish()方法的使用與解決app點擊“返回”(直接退出)
這篇文章主要介紹了Android Studio finish()方法的使用與解決app點擊“返回”(直接退出),本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-04-04

