es-jd
依赖
<properties>
<java.version>1.8</java.version>
<elasticsearch.version>7.8.0</elasticsearch.version>
</properties>
<dependencies>
<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.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</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>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.13.1</version>
</dependency>
</dependencies>
实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Goods {
private String name;
private String price;
private String img;
}
工具类方法
public List<Goods> getGoods(String keyword) throws IOException {
String url = "https://search.jd.com/Search?keyword=" + keyword;
Document document = Jsoup.parse(new URL(url), 30000);
Element element = document.getElementById("J_goodsList");
Elements elements = element.getElementsByTag("li");
List<Goods> List = new ArrayList<>();
for (Element li : elements) {
Elements el = li.getElementsByTag("img").eq(0);
String img = el.attr("src").equals("") ? el.attr("source-data-lazy-img") : el.attr("src");
String price = li.getElementsByClass("p-price").eq(0).text();
String name = li.getElementsByClass("p-name").eq(0).text();
Goods goods = new Goods(name, price, img);
List.add(goods);
}
return List;
}
配置config
@Configuration
public class ElasticSearchClientConfig {
@Bean
public RestHighLevelClient restHighLevelClient() {
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("localhost", 9200, "http")));
return client;
}
}
service层
@Service
public class GoodsService {
@Autowired
private HttpParseUtil httpParseUtil;
@Autowired
private RestHighLevelClient restHighLevelClient;
public boolean parseJD(String keyword) throws IOException {
List<Goods> list = httpParseUtil.parseJD(keyword);
BulkRequest request = new BulkRequest();
request.timeout("2m");
for (int i = 0; i < list.size(); i++) {
request.add(
new IndexRequest("jd_goods")
.source(JSON.toJSONString(list.get(i)), XContentType.JSON)
);
}
BulkResponse response = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
return !response.hasFailures();
}
public List<Map<String, Object>> searchJD(String keyword, int pageNo, int pageSize) throws IOException {
if (pageNo <= 1) {
pageNo = 1;
}
SearchRequest request = new SearchRequest("jd_goods");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//分页
sourceBuilder.from(pageNo);
sourceBuilder.size(pageSize);
//精准匹配
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", keyword);
sourceBuilder.query(termQueryBuilder);
sourceBuilder.timeout(TimeValue.timeValueSeconds(60));
request.source(sourceBuilder);
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
List<Map<String, Object>> list = new ArrayList<>();
for (SearchHit documentFields : response.getHits().getHits()) {
list.add(documentFields.getSourceAsMap());
}
return list;
}
//高亮搜索
public List<Map<String, Object>> searchJDHighLight(String keyword, int pageNo, int pageSize) throws IOException {
if (pageNo <= 1) {
pageNo = 1;
}
SearchRequest request = new SearchRequest("jd_goods");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//分页
sourceBuilder.from(pageNo);
sourceBuilder.size(pageSize);
//精准匹配
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", keyword);
sourceBuilder.query(termQueryBuilder);
sourceBuilder.timeout(TimeValue.timeValueSeconds(60));
//高亮
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("name");
highlightBuilder.preTags("<span style='color:red'>");
highlightBuilder.postTags("</span>");
sourceBuilder.highlighter(highlightBuilder);
request.source(sourceBuilder);
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
List<Map<String, Object>> list = new ArrayList<>();
for (SearchHit hit : response.getHits().getHits()) {
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
HighlightField name = highlightFields.get("name");
System.out.println("name->" + name);
Map<String, Object> map = hit.getSourceAsMap();
if (name != null) {
Text[] fragments = name.fragments();
String _name = "";
for (Text fragment : fragments) {
_name += fragment;
}
map.put("name", _name);
}
list.add(map);
}
return list;
}
}
controller层
@RestController
public class GoodsController {
@Autowired
GoodsService goodsService;
@GetMapping("/parse/{keyword}")
public boolean parseJD(@PathVariable("keyword") String keyword) throws IOException {
return goodsService.parseJD(keyword);
}
@GetMapping("/search/{keyword}/{pageNo}/{pageSize}")
public List<Map<String, Object>> searchJD(@PathVariable("keyword") String keyword,@PathVariable("pageNo") int pageNo,@PathVariable("pageSize") int pageSize) throws IOException {
return goodsService.searchJDHighLight(keyword, pageNo, pageSize);
}
}
前端页面
...
<form name="searchTop" class="mallSearch-form clearfix">
<fieldset>
<legend>京东搜索</legend>
<div class="mallSearch-input clearfix">
<div class="s-combobox" id="s-combobox-685">
<div class="s-combobox-input-wrap">
<input v-model="keyword" type="text" autocomplete="off" value="dd"
id="mq"
class="s-combobox-input" aria-haspopup="true">
</div>
</div>
<button type="submit" @click.prevent="search" id="searchbtn">搜索</button>
</div>
</fieldset>
</form>
,,,
<!-- 商品详情 -->
<div class="view grid-nosku">
<div class="product" v-for="result in results">
<div class="product-iWrap">
<!--商品封面-->
<div class="productImg-wrap">
<a class="productImg">
<img :src="result.img">
</a>
</div>
<!--价格-->
<p class="productPrice">
<em><b>¥</b>{{result.price}}</em>
</p>
<!--标题-->
<p class="productTitle">
<a> {{result.name}} </a>-->
<a v-html="result.name"></a>
</p>
<!-- 店铺名 -->
<div class="productShop">
<span>店铺名</span>
</div>
<!-- 成交信息 -->
<p class="productStatus">
<span>月成交<em>999笔</em></span>
<span>评价 <a>3</a></span>
</p>
</div>
</div>
</div>
...
<script>
new Vue({
el: '#app',
data: {
keyword: '',
results: []
},
methods: {
search() {
var keyword = this.keyword
axios.get('/search/' + keyword + '/1' + '/20').then(res=>{
this.results = res.data;
})
}
}
})
</script>