科百科
当前位置: 首页 范文大全

springboot开源分销商城(SpringBootESJsoup实现JD)

时间:2023-05-21 作者: 小编 阅读量: 2 栏目名: 范文大全

SpringBootESJsoup实现JD文章目录标题SpringBootESJsoup实现JD搜索项目效果1、功能概述利用Jsoup爬虫爬取JD商城的商品信息,并将商品信息存储在ElasticSearch中,同时利用请求进行全文检索,同时完。

文章目录
  • 标题SpringBoot ES Jsoup实现JD搜索

项目效果

1、功能概述

利用Jsoup爬虫爬取JD商城的商品信息,并将商品信息存储在ElasticSearch中,同时利用请求进行全文检索,同时完成高亮显示等功能。

2、工具简介

Jsoup:jsoup 是一款Java 的Html解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。

HttpClient:HttpClient 是Apache Jakarta Common 下一个子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。

3、操作步骤

3.1 创建SpringBoot项目

3.2 勾选对应的集成包

3.3 导入项目中需要的jar包依赖(这里需要注意Springboot版本与ES版本的冲突问题)

​ 版本对应 :

Spring Data Release Train

Spring Data Elasticsearch

Elasticsearch

Spring Framework

Spring Boot

2021.2 (Raj)

4.4.x

7.17.4

5.3.x

2.7.x

2021.1 (Q)

4.3.x

7.15.2

5.3.x

2.6.x

2021.0 (Pascal)

4.2.x[ 1 ]

7.12.0

5.3.x

2.5.x

2020.0 (Ockham)[ 1 ]

4.1.x[ 1 ]

7.9.3

5.3.2

2.4.x

Neumann[ 1 ]

4.0.x[ 1 ]

7.6.2

5.2.12

2.3.x

Moore[ 1 ]

3.2.x[ 1 ]

6.8.12

5.2.12

2.2.x

Lovelace[ 1 ]

3.1.x[ 1 ]

6.2.2

5.1.19

2.1.x

Kay[ 1 ]

3.0.x[ 1 ]

5.5.0

5.0.13

2.0.x

Ingalls[ 1 ]

2.1.x[ 1 ]

2.4.0

4.3.25

1.5.x

​ 需要导入maven依赖:

<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><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.75</version></dependency><!--解析网页 jsoup解析视频 tika--><dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.13.1</version></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.4.6</version></dependency><!-- HttpClient --><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId></dependency>

3.4 编写ES客户端配置类 ElasticSearchClientConfig (用于spring整体管理)

@Configurationpublic class ElasticSearchClientConfig {@Beanpublic RestHighLevelClient restHighLevelClient(){RestHighLevelClient restHighLevelClient = new RestHighLevelClient(RestClient.builder(new HttpHost("127.0.0.1", 9200)));return restHighLevelClient;}}

3.5 编写爬虫工具类 HtmlParseUtil

//html解析工具类public class HtmlParseUtil {public static void main(String[] args) throws IOException {List<Content> list = HtmlParseUtil.parseJDSearchKeyByPage("洗衣机", 2);System.out.println(list.size());}public static List<Content> parseJDSearchKeyByPage(String key,int page) throws IOException {List<Content> list = new ArrayList<>();for (int i = 1; i <=page ; i) {List<Content> itemList = HtmlParseUtil.parseJDSearchKey(key, i);list.addAll(itemList);}return list;}public static List<Content> parseJDSearchKey(String key,int page) throws IOException {//拼接URL路径和请求参数String url = UrlBuilder.create().setScheme("https").setHost("search.jd.com").addPath("Search").addQuery("keyword", key).addQuery("enc","utf-8").addQuery("page",String.valueOf(2*page-1)) //默认爬取前两页数据.build();URL url1 = new URL(url);HttpURLConnection httpConn = (HttpURLConnection) url1.openConnection();httpConn.setRequestMethod("GET");/**利用http模仿浏览器行为,防止被京东反爬虫程序**/httpConn.setRequestProperty("authority", "search.jd.com");httpConn.setRequestProperty("accept", "text/html,application/xhtml xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9");httpConn.setRequestProperty("accept-language", "zh-CN,zh;q=0.9");httpConn.setRequestProperty("cache-control", "max-age=0");httpConn.setRequestProperty("cookie", "__jdv=122270672|direct|-|none|-|1657610731752; __jdu=1657610731752947367087; pinId=zrLGvhk9izSm009P6x9LOw; pin=apple_ggUEIRS; unick=apple_ggUEIRS; ceshi3.com=000; _tp=70MDtYz0RbaKAAA4iyM/QQ==; _pst=apple_ggUEIRS; shshshfpb=daS4RVr0Yk9w65Hio31lN-g; shshshfpa=03fd05de-1795-e1be-7faa-dbe1342ebbcd-1657504705; rkv=1.0; areaId=12; ipLoc-djd=12-988-0-0; TrackID=1xjK9942JTH1cA13hCy9lpjoF4VUsywFztnHXMZa8fMqdod6dnvsJBqV2ZD7UVJXPOj_9eOcIbRSs8MdtE1dIc4M7Ie1oRPm-h1ZW-hdOnb9Gtb_DRX3_JGb_ZkJexJcQ; qrsc=3; PCSYCityID=CN_320000_320500_0; user-key=93bcac49-c4f4-4018-8b25-0766e0c16eda; cn=0; shshshfp=fc6aabe0109953d6062026a77f8bb1e5; __jda=122270672.1657610731752947367087.1657610732.1657610732.1657610732.1; __jdb=122270672.12.1657610731752947367087|1.1657610732; __jdc=122270672; shshshsID=fcfca37eb1dce4e7ebabf041ed253e70_6_1657612610164; thor=D83906BED82DBCAAD56166802034A7EB66575CF409BC09A49AFAF3487B79FEB995355C1A9063238C46E44EDF6CFED6A8324081B64A2FC4E00045BBAB6836FB7D4A6F24F6FBF97FE1F6A3014B93F3032242CB6FE9BF9D997B81005B34FA33DC1505BFB42E7DA2FE2D5991823CAEC187EE28A13F59C3698528BFD659FBAB4CFF16650B12DA4813475B5BF6F26CFCF2C198; 3AB9D23F7A4B3C9B=4YK7NHSJLWRZZ3CXJ4A22DRHHX7TAZBRBGGHDONJODT3TACJJJ65IS72HOSU4LFNHG6ZV3WAFDYORHCEBRJYYI6ZL4");httpConn.setRequestProperty("sec-ch-ua", "\".Not/A)Brand\";v=\"99\", \"Google Chrome\";v=\"103\", \"Chromium\";v=\"103\"");httpConn.setRequestProperty("sec-ch-ua-mobile", "?0");httpConn.setRequestProperty("sec-ch-ua-platform", "\"macOS\"");httpConn.setRequestProperty("sec-fetch-dest", "document");httpConn.setRequestProperty("sec-fetch-mode", "navigate");httpConn.setRequestProperty("sec-fetch-site", "none");httpConn.setRequestProperty("sec-fetch-user", "?1");httpConn.setRequestProperty("upgrade-insecure-requests", "1");httpConn.setRequestProperty("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36");InputStream responseStream = httpConn.getResponseCode() / 100 == 2? httpConn.getInputStream(): httpConn.getErrorStream();Scanner s = new Scanner(responseStream).useDelimiter("\\A");String response = s.hasNext() ? s.next() : "";Document document = Jsoup.parse(response);//Document document = Jsoup.connect(url).userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.100 Safari/537.36").cookie("wlfstk_smdl","4jxg7p5cy2jz7afp41rull7hc3y9mkjr").timeout(30000).get();Element j_goodsList = document.getElementById("J_goodsList");if(j_goodsList==null)returnnew ArrayList<>(); ;Element gl_warp= j_goodsList.getElementsByClass("gl-warp").get(0);ArrayList<Content> contents = new ArrayList<>();for (Element child : gl_warp.children()) {//img图片路径是存放在懒加载路径里面。String img =child.getElementsByTag("img").eq(0).attr("data-lazy-img");String price = child.getElementsByClass("p-price").eq(0).text();String name = child.getElementsByClass("p-name").eq(0).text();Content content = new Content();content.setImg(img);content.setTitle(name);content.setPrice(price);contents.add(content);}return contents;}}

3.6 编写前端页面 index.html

<!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org"><head><meta charset="utf-8"/><title>ES仿京东实战</title><link rel="stylesheet" th:href="@{/css/style.css}"/></head><body ><div><div><!-- 头部搜索 --><div><div ><div ><!-- Logo--><h1 ><img th:src="@{/images/jdlogo.png}" ></h1><div ><!--搜索--><div><form name="searchTop" ><fieldset><legend>天猫搜索</legend><div ><div><div ><input v-model="keyword" type="text" autocomplete="off" value="dd"aria-haspopup="true"></div></div><button type="submit"@click.prevent="searchKey">搜索</button></div></fieldset></form><ul ><li><a>Java</a></li><li><a>前端</a></li><li><a>Linux</a></li><li><a>大数据</a></li><li><a>理财</a></li></ul></div></div></div></div></div><!-- 商品详情页面 --><div ><div ><!-- 品牌分类 --><form ><div><div ><div ><div >品牌</div><div ><ul ><li><a href="#"></a></li><li><a href="#"> Java </a></li></ul></div></div></div></div></form><!-- 排序规则 --><div ><a >综合<i ></i></a><a >人气<i ></i></a><a >新品<i ></i></a><a >销量<i ></i></a><a >价格<i ></i><i ></i></a></div><!-- 商品详情 --><div ><!--<div >--><!--<div >--><!--<!–商品封面–>--><!--<div >--><!--<a >--><!--<img src="https://img.alicdn.com/bao/uploaded/i1/3899981502/O1CN01q1uVx21MxxSZs8TVn_!!0-item_pic.jpg">--><!--</a>--><!--</div>--><!--<!–价格–>--><!--<p >--><!--<em><b>¥</b>2590.00</em>--><!--</p>--><!--<!–标题–>--><!--<p >--><!--<a> dkny秋季纯色a字蕾丝dd商场同款连衣裙 </a>--><!--</p>--><!--<!– 店铺名 –>--><!--<div >--><!--<span>店铺: Java </span>--><!--</div>--><!--<!– 成交信息 –>--><!--<p >--><!--<span>月成交<em>999笔</em></span>--><!--<span>评价 <a>3</a></span>--><!--</p>--><!--</div>--><!--</div>--><divv-for="(item,index) in result" :key="index item"><div ><!--商品封面--><div ><a ><img :src="'http:' item.img"></a></div><!--价格--><p ><!--<em><b>¥</b>2590.00</em>--><em>{{item.price}}</em></p><!--标题--><p ><a v-html="item.title"></a><!--<a> { {item.title}}} </a>--></p><!-- 店铺名 --><div ><span>店铺: Java </span></div><!-- 成交信息 --><p ><span>月成交<em>999笔</em></span><span>评价 <a>3</a></span></p></div></div></div></div></div></div></div><script th:src="@{/js/jquery.min.js}"></script><script th:src="@{/js/axios.min.js}"></script><script th:src="@{/js/vue.min.js}"></script><script>new Vue({ el:"#app",data:{keyword:"",result:[]},methods:{async searchKey(){let keyword = this.keyword;console.log(keyword);let res =await axios.post("ES/Search",{keyword,pageSize:20,pageNo:1})console.log(res);if(res!=null&& res!=undefined){// alert("查询成功")this.result = res.data;}}}})</script></body></html>

3.7 创建商品pojo类 Content

@Datapublic class Content {private String img;private String title;private String price;}

3.8 编写爬虫同步逻辑代码

/** Controller层代码**/@Slf4j@RestController@RequestMapping("/ES")public class ESController {@ResourceEsDataSearchService esDataSearchService;/*** 导入数据进入es* @param keyword* @return* @throws Exception*/@GetMapping("/data/{keyword}")public booleanSynchronizeData(@PathVariable("keyword") String keyword) throws Exception {return esDataSearchService.SynchronizeData(keyword);}}/** Service层代码 **/@Servicepublic class EsDataSearchServiceImpl implements EsDataSearchService {@ResourceRestHighLevelClient restHighLevelClient;@Overridepublic boolean SynchronizeData(String keyword)throws Exception {List<Content> contents = HtmlParseUtil.parseJDSearchKeyByPage(keyword,2) ;//创建批量操作请求BulkRequest jd_goods = new BulkRequest();jd_goods.timeout("2m");//将爬取出来的数组同步进入esfor (Content content : contents) {//新增添加请求jd_goods.add(new IndexRequest("jd_goods").source(JSON.toJSONString(content), XContentType.JSON));}//批量请求BulkResponse response = restHighLevelClient.bulk(jd_goods, RequestOptions.DEFAULT);return !response.hasFailures();}}

注意:通过将爬取的数据转成数组,再通过es批量处理,将数据同步进入es

3.9 编写查询接口

/** Controller层代码**/@PostMapping("/Search")public List<Content> SearchData(@RequestBody SearchObject searchObject){return esDataSearchService.SearchData(searchObject,true);}/** Service层代码 **/@SneakyThrows@Overridepublic List<Content> SearchData(SearchObject searchObject,boolean flag) {SearchRequest request = new SearchRequest();request.indices("jd_goods");SearchSourceBuilder builder = new SearchSourceBuilder();//分页builder.from((searchObject.getPageNo()-1)*searchObject.getPageSize());builder.size(searchObject.getPageSize());HighlightBuilder highlightBuilder = new HighlightBuilder();//多个高亮显示highlightBuilder.requireFieldMatch(false);highlightBuilder.preTags("<span style='color:red;'>");highlightBuilder.postTags("</span>");highlightBuilder.field("title");builder.highlighter(highlightBuilder);//精准匹配 必须完全相同 否则无法展示TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", searchObject.getKeyword());MatchPhraseQueryBuilder queryBuilders = QueryBuilders.matchPhraseQuery("title", searchObject.getKeyword());builder.query(queryBuilders);//带中文的匹配BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();//boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("title",searchObject.getKeyword()));builder.query(boolQueryBuilder);builder.timeout(new TimeValue(60, TimeUnit.SECONDS));request.source(builder);//执行搜索SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//获取结果List<Content> res = new ArrayList<>();SearchHits hits = response.getHits();for (SearchHit hit : hits.getHits()) {Content content = JSON.parseObject(hit.getSourceAsString(), Content.class);Map<String, HighlightField> highlightFields = hit.getHighlightFields();HighlightField title = highlightFields.get("title");if(title!=null){Text[] fragments = title.fragments();StringBuffer str = new StringBuffer("");//利用StringBuffer拼接效率更高for (Text fragment : fragments) {str.append(fragment);}content.setTitle(str.toString());}res.add( content);}//没有就现插入if(res.size()==0&&flag){//第一次没有查找到数据,则进行一次数据爬取再执行查询。this.SynchronizeData(searchObject.getKeyword());Thread.sleep(1000);//线程睡眠1s 因为同步es数据是异步操作,等待同步完成。res =this.SearchData(searchObject,false);}return res;}

3.10 启动项目,通过 启动端口进行访问(记得打开ES服务)

Elasticsearch 是一个分布式、高扩展、高实时的搜索与 数据分析 引擎。它能很方便地使大量数据具有搜索、分析和探索的能力。

它可以做实时数据存储,es检索数据本身扩展性很好,可以扩展到上百台服务器,处理PB级别(大数据时代)的数据。

    推荐阅读
  • 温州驾照违章网上自助处理流程(温州驾照违章网上自助处理流程在哪里)

    查询方式一:小程序查询第一步:打开百度APP,搜索『百度城市服务』小程序,点击进入小程序页面百度城市服务小程序:点击『交通违章查询』国家政务服务平台小程序:点击交管服务—交通违章查询—选择办理的小程序第二步:授权登录,添加车辆第三步:输入车辆的相关信息,然后根据系统提示完成后面的申请流程查询方式二:温州交警官网查询官网查询入口:http://wzjj.wenzhou.gov.cn/查询流程如下第一

  • 大闸蟹要蒸多久才熟(大闸蟹要蒸多长时间才熟)

    下面内容希望能帮助到你,我们来一起看看吧!大闸蟹要蒸多久才熟15到20分钟左右。不过蒸大闸蟹的时间,与大闸蟹的大小相关,如不超过3两的螃蟹一般水开后蒸十分钟即可,4两的螃蟹水开后蒸12分钟,4两以上的螃蟹,就需要十五分钟左右,一般每多重一两,时间就需延长两分钟。如果不放心大闸蟹有没有蒸熟,可以把大闸蟹的后盖掰开,如果看到盖子内的蟹肉都凝固起来,那么就说明已经蒸熟煮透。

  • 大发慈悲是什么意思(大发慈悲的出处)

    下面内容希望能帮助到你,我们来一起看看吧!大发慈悲是什么意思:比喻起善心,做好事。

  • 榄菜朒碎四季豆怎么做(怎么做榄菜朒碎四季豆)

    以下内容大家不妨参考一二希望能帮到您!榄菜朒碎四季豆怎么做四季豆约300克,半肥瘦猪肉160克,榄菜约40克,红辣椒1只。将猪肉洗净剁碎,四季豆摘去头尾、去筋洗净,榄菜切碎,红椒切丝。先用榄菜及油起镬,然后加入猪肉碎炒熟。将四季豆炒熟,加入猪肉碎再炒片刻,调味后加红椒丝略炒即可上碟。

  • 魏婴真的爱蓝湛么(简单说说)

    魏婴真的爱蓝湛么?下面希望有你要的答案,我们一起来看看吧!《陈情令》是由郑伟文、陈家霖联合执导,肖战、王一博、孟子义、宣璐、汪卓成、于斌、刘海宽,朱赞锦,王皓轩主演,李若彤、陆剑民、黄子腾、修庆特别出演,沈晓海友情客串的古装仙侠剧。该剧根据墨香铜臭小说《魔道祖师》改编,以五大家族为背景,讲述了云梦江氏故人之子魏无羡和姑苏蓝氏含光君蓝忘机重遇,携手探寻往年真相,守护百姓和平安乐的故事。

  • 马的成语(马字成语及解析)

    膏车秣马[gàochēmòmǎ],我来为大家科普一下关于马的成语?明·屠隆《彩毫记·钦取回朝》:“羡调和鼎鼐,便膏车秣马好归来。”形容狂风大作,气候恶劣。也比喻工作走在群众前面,积极带头。

  • 受关注度最高的10款纯电车(当纯电车成为未来汽车主流趋势)

    即将在9月21日上市的小鹏G9交了一份答卷,引起四方围观,超快充技术应用,800V高压SiC平台首次量产上车,5分钟充电200公里……而小鹏汽车基于已成规模的充电网络,以及技术研发优势,率先跨进超快充时代。充电五分钟,续航200公里,充电15分钟,电量从10%到80%,与极速缩短的充电时间对应的,是更短的排队时间,纯电车充电排队问题不可忽视。

  • 郝蕾个人资料(郝蕾的资料大盘点)

    郝蕾个人资料郝蕾,1978年11月1日出生于吉林省通化市东昌区,中国内地女演员,毕业于上海戏剧学院表演系。2010年郝蕾凭电影《第四张画》荣获第47届台湾电影金马奖最佳女配角。2012年11月凭借《浮城谜事》中的陆洁一角入围金马奖最佳女主角奖。2014年郝蕾主演的文艺电影《亲爱的》和《黄金时代》先后上映,郝蕾再度获得关注。同年10月1日主演年代情感剧《我是你的眼》。2016年4月29日主演的电影《梦想合伙人》全国上映。

  • 少女适合用的护肤品(有哪些呢)

    少女适合用的护肤品青少年可以选择护肤品应以保湿润泽补水为主。这个年龄段的以保湿补水为主即可,没必要用功效型的护肤品。

  • 顶流刘德华(什么叫顶流这就是)

    9月3日,天王刘德华线上演唱会,引发巨大舆论热议。随后,艺人林子祥、梁咏琪以VCR出镜支持刘德华线上演唱会,一度将整个演唱会推向了制高点。事实上,此次刘德华创下的记录,估计将会成为娱乐圈的又一个天花板数字。自出道至今,41年来,刘德华几乎零绯闻。如今,60岁的刘德华再次王者归来,不仅是娱乐圈之幸,而且是粉丝之福。随着年龄的增加,刘德华也是极为关注新一代电影事业的发展。此次,刘德华2个小时创下了王炸的记录。