elasticsearch7.6.1版本+jsoup爬取京东商品数据并使用

实战: elasticsearch7.6.1版本+jsoup爬取京东商品数据并使用

前言

本文的实战需求是:从京东网页上拉去对应【关键字】的数据且存放到elasticsearch(以下简称es)中,然后通过Java操作es进行精准、分页、高亮搜索

【注意】:没有了解es的,建议先去了解es的基本使用

本文是基于对【狂神说Java】ElasticSearch7.6.x最新完整教程通俗易懂 课程的一个总结和分享,感兴趣的朋友可以到bilibili搜索狂神说Java;

https://www.bilibili.com/video/BV17a4y1x7zq

目录

  1. 前期准备
  2. 数据准备
  3. 业务编写
  4. 前后端分离
  5. 总结

1、前期准备

  1. elasticsearch7.6.1和head插件

    image

  2. 新建一个springboot项目

    image


    image

    点击finish,让项目自动导包即可

  3. 导入相关依赖

    如果想自己添加依赖,可以创建maven空项目,将这一段粘进去即可

    <parent>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-parent</artifactId>
    		<version>2.2.5.RELEASE</version>
    		<relativePath/> <!-- lookup parent from repository -->
    </parent>
    <dependencies>
    
    		<!-- jsoup解析网页 -->
    		<dependency>
    			<groupId>org.jsoup</groupId>
    			<artifactId>jsoup</artifactId>
    			<version>1.10.2</version>
    		</dependency>
    		<!-- jackson 用来把对象转换成json -->
    		<dependency>
    			<groupId>com.fasterxml.jackson.core</groupId>
    			<artifactId>jackson-databind</artifactId>
    			<version>2.10.2</version>
    		</dependency>
        	<!-- springboot集成elasticsearch -->
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    		</dependency>
        	
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-thymeleaf</artifactId>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-web</artifactId>
    		</dependency>
    
    		<dependency>
    			<groupId>org.projectlombok</groupId>
    			<artifactId>lombok</artifactId>
    			<optional>true</optional>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-test</artifactId>
    			<scope>test</scope>
    		</dependency>
    	</dependencies>
    
  4. 修改spring默认的es版本,这很重要,不然连接会报错

    当前导入的spring版本是2.2.5,默认的es版本是6.8.6

    image

    而我们的es版本是7.6.1,所以需要修改过来

    pom文件指定es版本

    <properties>
    	<elasticsearch.version>7.6.1</elasticsearch.version>
    </properties>
    
  5. 将测试页面导入到项目,后续会使用到axios和vue,所以也把对应的js文件导入

image

  1. 使用Java代码在ES中创建一个索引库

    ​ Java中操作es的步骤都可以在es官网文档中找到,从官方文档里面得知,我们在Java中要使用es,需要有一个客户端,基于es的版本,我们选择高版本客户端

    image-20210413221621521

    image-20210413221718205

    所以,我们应该条件反射,写一个配置类,把创建es客户端的步骤交给spring托管

    /**
     * @Author: Amg
     * @Date: Created in 15:12 2021/04/11
     * @Description: TODO
     */
    @Configuration
    public class MyConfiguration {
    
        @Bean
        public RestHighLevelClient restHighLevelClient() {
            RestHighLevelClient client = new RestHighLevelClient(
                    RestClient.builder(new HttpHost("localhost",9200,"http")));
            return client;
        }
    }
    

    然后创建一个索引
    image

ok~至此准备工作做好了,那么接下来就可以开干了!

2、数据准备

使用Jsoup爬取京东网站数据

首先我们找到在京东上搜索java:https://search.jd.com/Search?keyword=java

然后再搜索vue:https://search.jd.com/Search?keyword=vue

再搜索apple:https://search.jd.com/Search?keyword=apple

可以观察到,url固定前缀https://search.jd.com/Search?keyword= ,后续会用到

然后打开F12,点击左上角小鼠标,定位到商品栏目信息

image

image

通过上述观察,可以给出基本解析获取数据代码

/**
 * @Author: Amg
 * @Date: Created in 15:13 2021/04/11
 * @Description: 商品信息实体类
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class GoodsContent {

    private String price;

    private String title;

    private String img;
}


/**
 * @Author: Amg
 * @Date: Created in 15:27 2021/04/11
 * @Description: 使用Jsoup解析网页数据获取数据
 */
public class ParseHtmlUtil {

    //这里只针对京东搜索,如果需要改变url,请自行去查看网页构造结构,然后修改结构;
    //固定的url,后续只需要拼接对应的关键字即可
    private static final String BASE_URL = "https://search.jd.com/Search?keyword=";

    //当然如果这么写,每次都只能解析第一页的数据,所以如果要获取不同页面的数据,就可以通过循环来操作,这里有兴趣的朋友可以自行改造
    // private static final String BASE_URL = https://search.jd.com/Search?keyword=java&page=5
    
    /**
     * 按照 【关键词】搜索,并且返回具体的数据
     * @param keyword   关键词
     * @return 一个装载GoodsContent的list
     */
    public static List<GoodsContent> parseHtml(String keyword) {

        String url = BASE_URL + keyword;

        List<GoodsContent> list = new ArrayList<>();
        try {

            //获取浏览器Document对象,设置超时时间为30s
            final Document document = Jsoup.parse(new URL(url),30000);

            //通过此对象就可以解析网页标签结构,得到想要的信息;所以你需要做的就是分析网页结构

            //这就是刚刚我们定位到的【京东商品信息存放地方】
            final Elements elements = document.getElementById("J_goodsList").getElementsByTag("li");

            //进一步处理数据,把我们想要得数据给拿出来
            for (Element element : elements) {

                final String price = element.getElementsByClass("p-price").eq(0).text();
                final String title = element.getElementsByClass("p-name").eq(0).text();
                //图片如果直接找img src路径是获取不到的,因为类似京东这样子的网站,图片如此之多,肯定需要做懒加载,不然加载就会非常的慢
                //网页上在数据未加载完成的时候,可能只会存放一张静态的图片,等到数据获取回来,才会渲染上去,所以这里需要获取真正存放这个图片的路径
                final String img = element.getElementsByTag("img").eq(0).attr("data-lazy-img");

                GoodsContent goods = new GoodsContent();
                goods.setImg(img);
                goods.setTitle(title);
                goods.setPrice(price);

                list.add(goods);
            }

        } catch (Exception e) {
            System.err.println("爬去数据失败,请检查原因...");
            e.printStackTrace();
        }

        return list;
    }
}

3、业务编写

  1. 把解析出来的数据放到es指定的索引库中

    /**
    * 把数据存放到ES指定的索引库中
    * @param keyword  商品关键字
    * @param idx      索引库
    * @return         插入状态
    */
    public Boolean setDataToEs(String keyword,String idx) throws IOException {
    
            final List<GoodsContent> list = ParseHtmlUtil.parseHtml(keyword);
    
    
            //Java里面使用BulkRequest对象来批量插入数据,所以我们先new一个
            BulkRequest bulkRequest = new BulkRequest();
    
            for (int i = 0; i < list.size(); i++) {
                //遍历插入json数据
                bulkRequest.add(new IndexRequest(idx).source(OBJECT_MAPPER.writeValueAsString(list.get(i)),XContentType.JSON));
            }
    
            final BulkResponse bulkResponse = client.bulk(bulkRequest,RequestOptions.DEFAULT);
    
            //如果成功插入,返回true
            return !bulkResponse.hasFailures();
        }
    
    

    添加测试数据

    image


    image


    image

  2. 从指定索引库中搜索指定关键字的数据,实现分页,高亮显示

    /**
         * 从es中获取数据
         * @param keyword   es中的title
         * @param pageNo    第几页
         * @param pageSize  每页大小
         * @param esIdx     从那个索引库中取数据
         * @return          List<Map<String,Object>>
         */
        public List<Map<String,Object>> getDataFromEs(String keyword,int pageNo,int pageSize,String esIdx) throws IOException {
    
            if (pageNo <= 1) {
                pageNo = 1;
            }
    
            //构造搜索请求
            SearchRequest searchRequest = new SearchRequest(esIdx);
    
            //条件搜索
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    
            //精准匹配 如果需要其他条件搜索,例如模糊,前缀匹配等等,修改这里的规则
            final TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title",keyword);
            searchSourceBuilder.query(termQueryBuilder);
            searchSourceBuilder.timeout(new TimeValue(60,TimeUnit.SECONDS));
    
            //分页
            searchSourceBuilder.from(pageNo);
            searchSourceBuilder.size(pageSize);
    
            //把title匹配的值进行高亮显示,并且设置高亮样式
            final HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field("title");
            highlightBuilder.preTags("<span style='color:red;font-size:15px;font-weight:bold'>");
            highlightBuilder.postTags("</span>");
            searchSourceBuilder.highlighter(highlightBuilder);
    
    
            //把搜索条件放到搜索请求中
            searchRequest.source(searchSourceBuilder);
    
            //调用客户端执行搜索
            final SearchResponse searchResponse = client.search(searchRequest,RequestOptions.DEFAULT);
    
            //通过搜索回来的请求获取解析数据,并且放到放回的list中
            List<Map<String,Object>> list = new ArrayList<>();
            for (SearchHit documentFields : searchResponse.getHits().getHits()) {
    
                final Map<String,Object> sourceAsMap = documentFields.getSourceAsMap();
    
                final Map<String,HighlightField> highlightFields = documentFields.getHighlightFields();
                final Text[] texts = highlightFields.get("title").getFragments();
                //这里还需要额外处理高亮字段,让前面加的那段preTags和postTags生效(事实上现在的text,已经被标签给包裹起来了,只需要替换原来的值即可)
                String n_title = "";
                if (texts.length > 0) {
    
                    for (Text text : texts) {
                        n_title = text.string();
                    }
                }
                sourceAsMap.put("title",n_title);
                list.add(sourceAsMap);
            }
            return list;
        }
    

至此,es中也有了测试数据,而且测试获取数据接口能返回数据

⚠️注意观察,title现在是加上了span标签了

image


image

4、前后端分离

接口有了,数据有了,前台使用什么?Vue

使用axios发送请求到后端接口api,这里方便操作,页码定死为1,而且查询数据为10条,主要是验证好不好使

image


image

最终的效果

image


image


image

5、总结

项目本身复杂度不高,易上手,当然了,es更加高级的玩法,这里并没有完全展现出来,还需要不断的去学习摸索,如果有更加好玩的,我也会继续更新分享出来

最后说一下源码的获取

关注微信公众号 :码农Amg。回复:es实战,即可得到项目的所有源代码

感谢你的观看,我们下期再见!

image

原文地址:https://www.cnblogs.com/iamamg97

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 目录 连接 连接池产生原因 连接池实现原理 小结 TEMPERANCE:Eat not to dullness;drink not to elevation.节制
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 一个优秀的工程师和一个普通的工程师的区别,不是满天飞的架构图,他的功底体现在所写的每一行代码上。-- 毕玄 1. 命名风格 【书摘】类名用 UpperCamelC
今天犯了个错:“接口变动,伤筋动骨,除非你确定只有你一个人在用”。哪怕只是throw了一个新的Exception。哈哈,这是我犯的错误。一、接口和抽象类类,即一个对象。先抽象类,就是抽象出类的基础部分,即抽象基类(抽象类)。官方定义让人费解,但是记忆方法是也不错的 —包含抽象方法的类叫做抽象类。接口
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket一、引子文件,作为常见的数据源。关于操作文件的字节流就是 —FileInputStream&amp;FileOutputStream。
作者:泥沙砖瓦浆木匠网站:http://blog.csdn.net/jeffli1993个人签名:打算起手不凡写出鸿篇巨作的人,往往坚持不了完成第一章节。交流QQ群:【编程之美 365234583】http://qm.qq.com/cgi-bin/qm/qr?k=FhFAoaWwjP29_Aonqz
本文目录 线程与多线程 线程的运行与创建 线程的状态 1 线程与多线程 线程是什么? 线程(Thread)是一个对象(Object)。用来干什么?Java 线程(也称 JVM 线程)是 Java 进程内允许多个同时进行的任务。该进程内并发的任务成为线程(Thread),一个进程里至少一个线程。 Ja
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket在面向对象编程中,编程人员应该在意“资源”。比如?1String hello = &quot;hello&quot;; 在代码中,我们
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 这是泥瓦匠的第103篇原创 《程序兵法:Java String 源码的排序算法(一)》 文章工程:* JDK 1.8* 工程名:algorithm-core-le
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 目录 一、父子类变量名相同会咋样? 有个小故事,今天群里面有个人问下面如图输出什么? 我回答:60。但这是错的,答案结果是 40 。我知错能改,然后说了下父子类变
作者:泥瓦匠 出处:https://www.bysocket.com/2021-10-26/mac-create-files-from-the-root-directory.html Mac 操作系统挺适合开发者进行写代码,最近碰到了一个问题,问题是如何在 macOS 根目录创建文件夹。不同的 ma
作者:李强强上一篇,泥瓦匠基础地讲了下Java I/O : Bit Operation 位运算。这一讲,泥瓦匠带你走进Java中的进制详解。一、引子在Java世界里,99%的工作都是处理这高层。那么二进制,字节码这些会在哪里用到呢?自问自答:在跨平台的时候,就凸显神功了。比如说文件读写,数据通信,还
1 线程中断 1.1 什么是线程中断? 线程中断是线程的标志位属性。而不是真正终止线程,和线程的状态无关。线程中断过程表示一个运行中的线程,通过其他线程调用了该线程的 方法,使得该线程中断标志位属性改变。 深入思考下,线程中断不是去中断了线程,恰恰是用来通知该线程应该被中断了。具体是一个标志位属性,
Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocketReprint it anywhere u want需求 项目在设计表的时候,要处理并发多的一些数据,类似订单号不能重复,要保持唯一。原本以为来个时间戳,精确到毫秒应该不错了。后来觉得是错了,测试环境下很多一
纯技术交流群 每日推荐 - 技术干货推送 跟着泥瓦匠,一起问答交流 扫一扫,我邀请你入群 纯技术交流群 每日推荐 - 技术干货推送 跟着泥瓦匠,一起问答交流 扫一扫,我邀请你入群 加微信:bysocket01
Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocketReprint it anywhere u want.文章Points:1、介绍RESTful架构风格2、Spring配置CXF3、三层初设计,实现WebService接口层4、撰写HTTPClient 客户
Writer :BYSocket(泥沙砖瓦浆木匠)什么是回调?今天傻傻地截了张图问了下,然后被陈大牛回答道“就一个回调…”。此时千万个草泥马飞奔而过(逃哈哈,看着源码,享受着这种回调在代码上的作用,真是美哉。不妨总结总结。一、什么是回调回调,回调。要先有调用,才有调用者和被调用者之间的回调。所以在百
Writer :BYSocket(泥沙砖瓦浆木匠)一、什么大小端?大小端在计算机业界,Endian表示数据在存储器中的存放顺序。百度百科如下叙述之:大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加
What is a programming language? Before introducing compilation and decompilation, let&#39;s briefly introduce the Programming Language. Programming la
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket泥瓦匠喜欢Java,文章总是扯扯Java。 I/O 基础,就是二进制,也就是Bit。一、Bit与二进制什么是Bit(位)呢?位是CPU
Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocket一、前言 泥瓦匠最近被项目搞的天昏地暗。发现有些要给自己一些目标,关于技术的目标:专注很重要。专注Java 基础 + H5(学习) 其他操作系统,算法,数据结构当成课外书博览。有时候,就是那样你越是专注方面越