JD商城实战

新建Springboot initializr项目

导入es、fastjson等pom下的依赖

爬虫

数据问题?数据库获取,消息队列中获取,都可以成为数据源,或者爬虫

爬取数据:(获取请求返回的页面信息,筛选出我们想要的数据就可以了)

jsoup包:用于解析网页,不能爬电影

新建一个utils包放网页解析的工具类

在这里插入图片描述

本质的请求是:

https://search.jd.com/Search?keyword=java

在这里插入图片描述

所有在Js中的方法这里都可以使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.kun.utils;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

public class HtmlParseUtil {
public static void main(String[] args) throws IOException {
// 获取请求 https://search.jd.com/Search?keyword=java
String url = "https://search.jd.com/Search?keyword=java";
//解析网页 Jsoup返回的就是浏览器Document对象
Document document = Jsoup.parse(new URL(url), 30000);
Element element = document.getElementById("J_goodsList");
System.out.println(element.html());
//获取所有的li元素/标签
Elements elements = element.getElementsByTag("li");
//获取元素中的内容 eq获取当前第一个元素,获取src属性
for (Element el : elements) {
//关于这种图片特别多的网站,所有的图片都是延迟加载的!
String img = el.getElementsByTag("img").eq(0).attr("src");
String price = el.getElementsByClass("p-price").eq(0).text();
String title = el.getElementsByClass("p-name").eq(0).text();

System.out.println("===============================");
System.out.println(img);
System.out.println(price);
System.out.println(title);
}
}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

输出结果

在这里插入图片描述

注意:

在图片较多的网站中,图片往往是延迟加载的,注意看图片的属性:

在这里插入图片描述

将获取到的元素 封装成对象,新建pojo,Content.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.kun.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Content {
private String title;
private String img;
private String price;
//可以自己添加属性
}

再次封装工具类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package com.kun.utils;

import com.kun.pojo.Content;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
@Component //丢进Springboot中
public class HtmlParseUtil {
public static void main(String[] args) throws Exception {
new HtmlParseUtil().parseJD("java").forEach(System.out::println);
}


public List<Content> parseJD(String keywords) throws Exception {
// 获取请求 https://search.jd.com/Search?keyword=java
String url = "https://search.jd.com/Search?keyword=" + keywords;
//解析网页 Jsoup返回的就是浏览器Document对象
Document document = Jsoup.parse(new URL(url), 30000);
//所有你在js中可以使用的方法,这里都可以使用
Element element = document.getElementById("J_goodsList");
// System.out.println(element.html());
//获取所有的li元素/标签
Elements elements = element.getElementsByTag("li");

//封装对象
ArrayList<Content> goodsList = new ArrayList<Content>();
//获取元素中的内容 eq获取当前第一个元素,获取src属性
for (Element el : elements) {
//关于这种图片特别多的网站,所有的图片都是延迟加载的!
String img = el.getElementsByTag("img").eq(0).attr("src");
String price = el.getElementsByClass("p-price").eq(0).text();
String title = el.getElementsByClass("p-name").eq(0).text();

Content content = new Content();
content.setImg(img);
content.setPrice(price);
content.setTitle(title);
goodsList.add(content);
// System.out.println("===============================");
// System.out.println(img);
// System.out.println(price);
// System.out.println(title);
}
return goodsList;
}
}

编写业务层service:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.kun.service;

import com.alibaba.fastjson.JSON;
import com.kun.pojo.Content;
import com.kun.utils.HtmlParseUtil;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;

import java.util.List;
//业务编写
@Service
public class ContentService {
@Autowired
private RestHighLevelClient restHighLevelClient;


//1.解析数据放入es索引中
public Boolean parseContent(String keywords) throws Exception {
List<Content> contents = new HtmlParseUtil().parseJD(keywords);
//把查询的数据放入我们的es中
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.timeout("2m");
//批量插入
for (int i = 0; i < contents.size(); i++) {
bulkRequest.add(
new IndexRequest("jd_goods")
.source(JSON.toJSONString(contents.get(i)), XContentType.JSON));
}

BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
return !bulk.hasFailures();
}
}

测试:由于这个文件中又Autowire,所以就算建了主函数psvm,也不能测,必须启动服务;

直接用controller来测:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.kun.controller;


import com.kun.service.ContentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ContentController {
@Autowired
private ContentService contentService;

@GetMapping("/parse/{keyword}")
public Boolean parse(@PathVariable("keyword") String keywords) throws Exception {
return contentService.parseContent(keywords);
}
}

再在业务层中实现搜索功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 2. 获取数据实现搜索功能
public List<Map<String,Object>> searchPage(String keyword,int pageNo,int pageSize) throws IOException {
if(pageNo<=1){
pageNo = 1;
}
//条件搜索
SearchRequest searchRequest = new SearchRequest("jd_goods");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//分页
sourceBuilder.from(pageNo);
sourceBuilder.size(pageSize);
//精准匹配
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword);
sourceBuilder.query(termQueryBuilder);
sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
//执行搜索
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//解析结果
ArrayList<Map<String,Object>> list = new ArrayList<>();
for (SearchHit documentFields : searchResponse.getHits().getHits()) {
list.add(documentFields.getSourceAsMap());
}
return list;
}

用Controller来测:

1
2
3
4
5
6
@GetMapping("/parse/{keyword}/{pageNo}/{pageSize}")
public List<Map<String,Object>> search(@PathVariable("keyword") String keyword,
@PathVariable("pageNo")int pageNo,
@PathVariable("pageSize") int pageSize) throws IOException {
return contentService.searchPage(keyword, pageNo, pageSize);
}

前后端分离

先在一个任意包下npm install vue生成vue文件,将内部一些js包导入Springboot项目中;axios.min.js;vue.min.js

在这里插入图片描述

在这里插入图片描述

在前端每个商品中得到result值

在这里插入图片描述

搜索高亮

修改业务层ContentService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
 //3. 新增高亮功能
public List<Map<String,Object>> searchPageHighlightBuilder(String keyword,int pageNo,int pageSize) throws Exception {
parseContent(keyword);

if (pageNo <= 1) {
pageNo = 1;
}
//条件搜索
SearchRequest searchRequest = new SearchRequest("jd_goods");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//分页
sourceBuilder.from(pageNo);
sourceBuilder.size(pageSize);
//精准匹配
// TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword);
// sourceBuilder.query(termQueryBuilder);
// sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

//match匹配 可以支持中文搜索
MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder("title", keyword);
sourceBuilder.query(matchQueryBuilder);
sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));//超时
//高亮
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("title"); //高亮的字段
highlightBuilder.requireFieldMatch(false);//如果一句里面有多个关键词高亮,则只显示第一个
highlightBuilder.preTags("<span style='color:red'>");
highlightBuilder.postTags("</span>");
sourceBuilder.highlighter(highlightBuilder);
//执行搜索
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//解析结果
ArrayList<Map<String, Object>> list = new ArrayList<>();
for (SearchHit hit : searchResponse.getHits().getHits()) {

Map<String, HighlightField> highlightFields = hit.getHighlightFields(); //获取到高亮字段
HighlightField title = highlightFields.get("title");
Map<String, Object> sourceAsMap = hit.getSourceAsMap(); //原来的结果!要在结果里面将高亮置换一下
//解析高亮的字段 将原来的字段换为我们高亮的字段即可
if (title != null) {
Text[] fragments = title.fragments();
String n_title = "";
for (Text text : fragments) {
n_title += text;
}
sourceAsMap.put("title", n_title);//高亮字段替换掉原来的内容即可!
}
list.add(sourceAsMap);
}
return list;
}

效果

在这里插入图片描述