基于RxJava2實(shí)現(xiàn)的簡(jiǎn)單圖片爬蟲的方法
今年十月份以來,跟朋友嘗試導(dǎo)入一些圖片到tensorflow來生成模型,這就需要大量的圖片。剛開始我只寫了一個(gè)簡(jiǎn)單的HttpClient程序來抓取圖片,后來為了通用性索性寫一個(gè)簡(jiǎn)單的圖片爬蟲程序。它可以用于抓取單張圖片、多張圖片、某個(gè)網(wǎng)頁下的所有圖片、多個(gè)網(wǎng)頁下的所有圖片。
github地址:https://github.com/fengzhizi715/PicCrawler
這個(gè)爬蟲使用了HttpClient、RxJava2以及Java 8的一些特性。它支持一些簡(jiǎn)單的定制,比如定制User-Agent、Referer、Cookies等。
一.下載安裝:
對(duì)于Java項(xiàng)目如果使用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ò)請(qǐng)求的超時(shí)時(shí)間。fileStrategy()表示存放的目錄、文件使用的格式、生成的文件時(shí)使用何種策略。repeat()表示對(duì)該圖片請(qǐng)求重復(fù)的次數(shù)。
PicCrawler支持多種文件的生成策略,比如隨機(jī)生成文件名、從1開始自增長(zhǎng)地生成文件名、生成指定的文件名等等。
下圖顯示了使用該程序?qū)δ瞅?yàn)證碼的圖片下載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中,可以對(duì)文件做一些后續(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 下載某個(gè)網(wǎng)頁的全部圖片
String url = "http://www.jianshu.com/u/4f2c483c12d8"; // 針對(duì)某一網(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);
使用上面的程序,對(duì)我簡(jiǎn)書主頁上的圖片進(jìn)行抓取。

2.4 下載多個(gè)網(wǎng)頁的全部圖片
List<String> urls = new ArrayList<>(); // 多個(gè)網(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);
下載個(gè)人簡(jiǎn)書主頁上的圖以及開發(fā)者頭條的圖片。

三. 部分源碼解析
3.1 下載某個(gè)網(wǎng)頁的全部圖片
downloadWebPageImages()方法表示下載某個(gè)url的全部圖片。
/**
* 下載整個(gè)網(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ò)請(qǐng)求、解析出當(dāng)前頁面中包含的圖片路徑、下載這些圖片。
第一步,創(chuàng)建網(wǎng)絡(luò)請(qǐng)求使用了HttpClient。
public CloseableHttpResponse createHttpWithGet(String url) {
// 獲取客戶端連接對(duì)象
CloseableHttpClient httpClient = getHttpClient();
// 創(chuàng)建Get請(qǐng)求對(duì)象
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í)行請(qǐng)求
try {
response = httpClient.execute(httpGet);
} catch (IOException e) {
e.printStackTrace();
}
return response;
}
第二步,將返回的response轉(zhuǎn)換成String類型,使用jsoup將帶有圖片的鏈接全部過濾出來。
jsoup 是一款Java 的HTML解析器,可直接解析某個(gè)URL地址、HTML文本內(nèi)容。它提供了一套非常省力的API,可通過DOM,CSS以及類似于jQuery的操作方法來取出和操作數(shù)據(jù)。
private List<String> parseHtmlToImages(CloseableHttpResponse response) {
// 獲取響應(yīng)實(shí)體
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"))) { // 圖片的絕對(duì)路徑不為空
String picUrl = src.attr("abs:src");
log.info(picUrl);
urls.add(picUrl);
} else if (Preconditions.isNotBlank(src.attr("src"))){ // 圖片的相對(duì)路徑不為空
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("釋放鏈接錯(cuò)誤");
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 下載多個(gè)網(wǎng)頁的全部圖片
downloadWebPageImages()方法還支持傳List集合,表示多個(gè)網(wǎng)頁的地址。
/**
* 下載多個(gè)網(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()));
}
}
在這里其實(shí)用到了ParallelFlowable,因?yàn)閜arallel()可以把Flowable轉(zhuǎn)成ParallelFlowable。
總結(jié)
PicCrawler 是一個(gè)簡(jiǎn)單的圖片爬蟲,目前基本可以滿足我的需求。未來要是有新的需求,我會(huì)不斷添加功能。
在做PicCrawler時(shí),其實(shí)還做了一個(gè)ProxyPool用于獲取可用代理池的庫(kù),它也是基于RxJava2實(shí)現(xiàn)的。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- RxJava2.x實(shí)現(xiàn)定時(shí)器的實(shí)例代碼
- 詳解RxJava2 Retrofit2 網(wǎng)絡(luò)框架簡(jiǎn)潔輕便封裝
- RxJava2.x+ReTrofit2.x多線程下載文件的示例代碼
- Android 使用 RxJava2 實(shí)現(xiàn)倒計(jì)時(shí)功能的示例代碼
- 基于Retrofit2+RxJava2實(shí)現(xiàn)Android App自動(dòng)更新
- RxJava2配置及使用詳解
- Android 用RxBinding與RxJava2實(shí)現(xiàn)短信驗(yàn)證碼倒計(jì)時(shí)功能
- RxJava2和Retrofit2封裝教程(整潔、簡(jiǎn)單、實(shí)用)
- Rxjava2_Flowable_Sqlite_Android數(shù)據(jù)庫(kù)訪問實(shí)例
- 談?wù)凴xJava2中的異常及處理方法
相關(guān)文章
Android開發(fā)中Activity的生命周期及加載模式詳解
這篇文章主要介紹了Android開發(fā)中Activity的生命周期及加載模式詳解的相關(guān)資料,非常不錯(cuò)具有參考借鑒價(jià)值,需要的朋友可以參考下2016-05-05
Android輸入框?qū)崟r(shí)模糊搜索效果的示例代碼
這篇文章主要介紹了Android輸入框?qū)崟r(shí)模糊搜索效果的示例代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
EasyValidate優(yōu)雅地校驗(yàn)提交數(shù)據(jù)完整性
這篇文章主要介紹了EasyValidate優(yōu)雅地校驗(yàn)提交數(shù)據(jù)完整性,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-12-12
Android帶進(jìn)度條的文件上傳示例(使用AsyncTask異步任務(wù))
這篇文章主要介紹了Android帶進(jìn)度條的文件上傳示例(使用AsyncTask異步任務(wù)),使用起來比較方便,將幾個(gè)方法實(shí)現(xiàn)就行,感興趣的小伙伴們可以參考一下。2016-11-11
淺析Android Studio 3.0 升級(jí)各種坑(推薦)
本文是小編給大家收藏整理的關(guān)于Android Studio 3.0 升級(jí)后遇到的一些坑,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧2017-11-11
Android?Studio實(shí)現(xiàn)簡(jiǎn)單計(jì)算器開發(fā)
這篇文章主要為大家詳細(xì)介紹了Android?Studio實(shí)現(xiàn)簡(jiǎn)單計(jì)算器開發(fā),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05

