基于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)建镊靴,由于默認不是使用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次睦疫。


下載200張驗證碼的圖片.png
  1. 使用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);
  1. 使用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.reibang.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);

使用上面的程序宛官,對我簡書主頁上的圖片進行抓取。


簡書的主頁.png

2.4 下載多個網(wǎng)頁的全部圖片

        List<String> urls = new ArrayList<>(); // 多個網(wǎng)頁的集合

        urls.add("http://www.reibang.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ā)者頭條的圖片瓦糕。


多個網(wǎng)址的圖片下載.png

三. 部分源碼解析

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)的煮纵。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末懂鸵,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子行疏,更是在濱河造成了極大的恐慌匆光,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酿联,死亡現(xiàn)場離奇詭異终息,居然都是意外死亡,警方通過查閱死者的電腦和手機贞让,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門周崭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人喳张,你說我怎么就攤上這事续镇。” “怎么了销部?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵摸航,是天一觀的道長。 經(jīng)常有香客問我舅桩,道長酱虎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任擂涛,我火速辦了婚禮读串,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘撒妈。我一直安慰自己恢暖,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布狰右。 她就那樣靜靜地躺著胀茵,像睡著了一般。 火紅的嫁衣襯著肌膚如雪挟阻。 梳的紋絲不亂的頭發(fā)上琼娘,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天峭弟,我揣著相機與錄音,去河邊找鬼脱拼。 笑死瞒瘸,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的熄浓。 我是一名探鬼主播情臭,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼赌蔑!你這毒婦竟也來了俯在?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤娃惯,失蹤者是張志新(化名)和其女友劉穎赠涮,沒想到半個月后槽畔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烤芦,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡涕蜂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了皿哨。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浅侨。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖证膨,靈堂內(nèi)的尸體忽然破棺而出如输,到底是詐尸還是另有隱情,我是刑警寧澤央勒,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布挨决,位于F島的核電站,受9級特大地震影響订歪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜肆捕,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一刷晋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧慎陵,春花似錦眼虱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至润梯,卻和暖如春过牙,著一層夾襖步出監(jiān)牢的瞬間甥厦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工寇钉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留刀疙,地道東北人。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓扫倡,卻偏偏與公主長得像谦秧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子撵溃,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理疚鲤,服務(wù)發(fā)現(xiàn),斷路器缘挑,智...
    卡卡羅2017閱讀 134,656評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,129評論 25 707
  • 今天又來到了武漢參加明天普通話的考試集歇,為了這個普通話,我付出了太多卖哎。吳先生也幫助我不少鬼悠。 這一次,他又幫我訂酒店亏娜,...
    麥盾可閱讀 234評論 0 0
  • 我是個面癱寡言的北方人焕窝,我在南方過活著。 我生來薄情寡義维贺,父母親情我一一看在眼里它掂,記在心里,卻從來沒有...
    樹下閑人閱讀 736評論 9 15
  • 國民岳父韓寒是微博時代前段子手溯泣,大電影《萬萬沒想到》藝術(shù)總監(jiān)兼白龍馬客串咖虐秋。 叫獸易小星是網(wǎng)劇《萬萬沒想到》導(dǎo)演,...
    暴娛梨花陣閱讀 529評論 0 3