Java网络爬虫实操(4)

作者: 风行者1024 | 来源:发表于2018-02-18 21:34 被阅读117次

    上一篇:Java网络爬虫实操(3)

    本篇文章继续围绕NetDiscovery框架中pipeline的用法,结合另一个专门爬图片的框架PicCrawler,实现图片的批量下载和信息的存储。顺便介绍一下Vert.X框架中的mongo基础操作。

    1) 目标任务

    • 找一个有很多美女图片的网址
    • 解析出要下载的图片链接,放到一个list中
    • 把list传到图片爬虫框架,几行代码搞定
    • 把需要的信息存储到mongodb
        //参考以前的文章,本篇要新增的依赖包
        implementation 'io.vertx:vertx-mongo-client:3.5.0'
        implementation 'com.cv4j.piccrawler:crawler:1.0.0'
    

    2) 解析网页

    目标网页
    package com.sinkinka.parser;
    
    import com.cv4j.netdiscovery.core.domain.Page;
    import com.cv4j.netdiscovery.core.domain.ResultItems;
    import com.cv4j.netdiscovery.core.parser.Parser;
    import com.cv4j.netdiscovery.core.parser.selector.Selectable;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class GirlParser implements Parser {
    
        @Override
        public void process(Page page) {
    
            String xpath = "//div[@class='contLeftA']/ul[@class='artCont cl']/li";
            List<Selectable> liList = page.getHtml().xpath(xpath).nodes();
            List<String> imgUrlList = new ArrayList<>();
            for(Selectable li : liList) {
                String imageUrl = li.xpath("//img/@src").get();
                imgUrlList.add(imageUrl);
            }
    
            ResultItems resultItems = page.getResultItems();
            resultItems.put("needDownloadImage", imgUrlList);
        }
    }
    
    

    3) 下载图片

    package com.sinkinka.pipeline;
    
    import com.cv4j.netdiscovery.core.domain.ResultItems;
    import com.cv4j.netdiscovery.core.pipeline.Pipeline;
    import com.cv4j.piccrawler.PicCrawlerClient;
    import com.cv4j.piccrawler.download.strategy.FileGenType;
    import com.cv4j.piccrawler.download.strategy.FileStrategy;
    
    import java.util.List;
    
    public class SaveGirlImage implements Pipeline {
    
        @Override
        public void process(ResultItems resultItems) {
            // 1.下载图片
            List<String> urls = resultItems.get("needDownloadImage");
            PicCrawlerClient.get()
                    .timeOut(5000)
                    .fileStrategy(new FileStrategy() {
                        @Override
                        public String filePath() {
                            return "temp";//保存图片的文件夹
                        }
    
                        @Override
                        public String picFormat() {
                            return "jpg";//保存图片的格式
                        }
    
                        @Override
                        public FileGenType genType() {
                            return FileGenType.AUTO_INCREMENT;//保存图片的文件名生成规则
                        }
                    })
                    .build()
                    .autoReferer()       //自动设置refer
                    .downloadPics(urls); //最关键的一行代码,把list扔进去就可以了
    
            //2. 设置信息给下一个pipeline SaveGirlImageLog使用
            resultItems.put("savecount", urls.size());
        }
    }
    
    批量下载到本地的图片

    4) 保存信息

    package com.sinkinka.pipeline;
    
    import com.cv4j.netdiscovery.core.domain.ResultItems;
    import com.cv4j.netdiscovery.core.pipeline.Pipeline;
    import io.vertx.core.AsyncResult;
    import io.vertx.core.Handler;
    import io.vertx.core.json.JsonObject;
    import io.vertx.ext.mongo.MongoClient;
    
    import java.util.Date;
    
    public class SaveGirlImageLog implements Pipeline {
    
        private MongoClient mongoClient;  //基于vertx的对象
        private String collectionName;
    
        public SaveGirlImageLog(MongoClient mongoClient, String collectionName){
            this.mongoClient = mongoClient;
            this.collectionName = collectionName;
        }
    
        @Override
        public void process(ResultItems resultItems) {
            //设置要保存的数据
            JsonObject jsonObject = new JsonObject();
            jsonObject.put("savecount", Integer.parseInt(resultItems.get("savecount").toString()));
            jsonObject.put("savetime", new Date().getTime());
    
            //1:存储到mongo数据库里
            mongoClient.save(collectionName, jsonObject, new Handler<AsyncResult<String>>() {
                @Override
                public void handle(AsyncResult<String> response) {
                    if (response.succeeded()) {
                        System.out.println("save success, new id=" + response.result());
                    } else {
                        System.out.println("save failure");
                        response.cause().printStackTrace();
                    }
                }
            });
    
            //2:另一种lambda表达式的写法
    //        mongoClient.save(collectionName, jsonObject, response -> {
    //            if (response.succeeded()) {
    //                System.out.println("save success, new id=" + response.result());
    //            } else {
    //                System.out.println("save failure");
    //                response.cause().printStackTrace();
    //            }
    //        });
        }
    }
    
    
    存到mongo里的数据

    5) 运行程序

    • 一个parser类GirlParser
    • 两个pipeline类SaveGirlImage、SaveGirlImageLog
    • Vert.X的MongoClient,异步非阻塞的方法
    package com.sinkinka;
    
    import com.cv4j.netdiscovery.core.Spider;
    import com.sinkinka.parser.GirlParser;
    import com.sinkinka.pipeline.SaveGirlImage;
    import com.sinkinka.pipeline.SaveGirlImageLog;
    import io.vertx.core.Vertx;
    import io.vertx.core.json.JsonObject;
    import io.vertx.ext.mongo.MongoClient;
    
    public class GirlSpider {
    
        public static void main(String[] args) {
            String url = "http://www.woyaogexing.com/touxiang/nv/2018/586210.html";
            //创建一个vertx的mongoClient,SaveLog
            MongoClient mongoClient = MongoClient.createShared(Vertx.vertx(), getDatabaseConfig());
            
            Spider.create()
                    .name("getGirlImage")
                    .url(url)
                    .parser(new GirlParser())
                    .pipeline(new SaveGirlImage())
                    .pipeline(new SaveGirlImageLog(mongoClient, "SaveLog"))
                    .run();
        }
    
        public static JsonObject getDatabaseConfig() {
            JsonObject jsonObject = new JsonObject();
            jsonObject.put("connection_string", "mongodb://127.0.0.1:27017");
            jsonObject.put("db_name", "test");
    //        jsonObject.put("username", "");
    //        jsonObject.put("password", "");
            return jsonObject;
        }
    }
    
    

    6) 基于Vert.X的mongo操作

    本篇的mongo操作使用的类是:io.vertx.ext.mongo.MongoClient
    Vert.X的MongoClient提供的方法都是异步非阻塞的,非常灵活:

    MongoClient
    建议大家去了解一下增删改查,都有一个Handler<AsyncResult<[Type]>>
    参考:http://vertx.io/docs/vertx-mongo-client/java/

    7) 总结

    利用框架我们能快捷的实现一个图片爬虫程序,本地有开发环境的话,几分钟就能搞定。以上例子仅仅是抛砖引玉,大家自由发挥其中的使用场景吧。

    图片爬虫框架PicCrawler还有很多强大的用法,大家有兴趣可以去github上详细了解吧。

    下一篇:Java网络爬虫实操(5)

    相关文章

      网友评论

      • weir_will:赞,自己以前使用过jsoup抓过页面,请问对于 图虫 等网站好像有防爬虫机制,你是怎么处理的?ps 自己已经设置了请求头了…
        风行者1024:你好,感谢留言。图虫网站没研究过。爬与发爬都要具体问题具体分析了。
      • Alien的小窝:赞,框架看起来有借鉴于webMagic,我也在这个框架上面做过精简,为了便于移植到Android平台,有时间学习下你框架的优点进一步完善我的那个框架!
      • 风行者1024:巧笑倩兮,美目盼兮

      本文标题:Java网络爬虫实操(4)

      本文链接:https://www.haomeiwen.com/subject/ffibtftx.html