您好,登錄后才能下訂單哦!
今年十月份以來,跟朋友嘗試導入一些圖片到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次。
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);
使用上面的程序,對我簡書主頁上的圖片進行抓取。
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);
下載個人簡書主頁上的圖以及開發者頭條的圖片。
三. 部分源碼解析
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("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的性能也好于傳統的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實現的。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。