此处没有安装步骤,安装过程挺简单,开箱即用,只是安装过程有一些坑,此处只有碎碎念,随记。
目录
0、前述。
1、部署过程的一些问题。
2、搜索使用的技术。
3、freenom域名。
4、部分代码。
0、前述。
趁着双11优惠,弄了一台1核2G的阿里云服务器,琢磨着部署点什么东西上去,刚好最近在学elasticsearch,就把做的一个搜索部署上去好了。
访问地址:
效果图:
1、部署过程的一些问题。(1)elasticsearch、kibana、IK分词器,三者版本要一致,都用相同的版本。
特别是elasticsearch与IK的版本要一致,否则ES直接启动不了。
使用的elasticsearch版本:7.15.1。
使用的kibana版本:7.15.1。
使用的ik分词器版本:7.15.1。
(2)elasticsearch 7.x版本,JDK必须使用1.8以上版本,官方推荐使用jdk 11版本。
在安装ES之前,我已经在服务器上安装了一个JDK 1.8的版本,在window上jdk 1.8搭配elasticsearch7.15.0是可以运行的,在服务器上ES启动不了,最终服务器的jdk换成了jdk 11。
(3)启动ES,不要使用root用户,创建一个专门用于elasticsearch的用户,否则启动不了。
例如:创建一个名称为elastic的用户,添加到elastic组中。
groupadd elastic useradd els -g elastic passwd elastic chown -R elastic:elastic /root
使用命令切换用户到elastic,然后启动ES。
su elastic
在window下不是管理员用户可以启动ES。
(4)服务器内存太小,只有2G。ES启动后不久后自动关闭,被系统kill掉了。或启动之后占满了内存,系统卡死。
修改elasticsearch的jvm内存。
vim elasticsearch-7.15.1/config/jvm.options
找到配置内容。
## -Xms4g ## -Xmx4g
去掉#号,修改配置为如下。
-Xms256m -Xmx256m
(5)安装kibana,修改kibana的jvm内存。
vim kibana-7.15.1-linux-x86_64/config/node.options
找到配置内容。
#--max-old-space-size=4096
去掉#号,修改配置为如下:
--max-old-space-size=400
(6)部署在服务器上的kibana,通过浏览器访问不到。
修改配置kibana.yml文件。
vim kibana-7.15.1-linux-x86_64/config/kibana.yml
找到配置内容。
#server.host: "localhost"
去掉#号,修改成服务器的内网IP地址,是内网IP地址,不是外网IP地址。默认kibana为localhost,只有安装kibana的服务器可以访问,其他访问不了。
修改配置:
server.host: "172.x.x.x"
修改完成之后,还是访问不到kibana。
修改阿里云服务器安全组规则访问,开启防火墙相关端口。
kibana.yml默认访问端口是5601。
#server.port: 5601
云服务器 ECS:
网络与安全-->安全组-->配置规则-->入方向。
(6)使用了jsoup,爬取不到数据,连接超时timeout。
jsoup端口随机生成的,。。。开启服务器出方向端口。
云服务器 ECS:
网络与安全-->安全组-->配置规则-->出方向。
(1)使用的主要技术elasticsearch、kibana、jsoup、spring boot。
次要技术:lombok、fastjson、selenium。
jsoup用来抓取解析数据,elasticsearch用来存储数据。kibana用来建ES索引,查看数据。
selenium用来配合Firefox浏览器等网页加载完成,再用jsoup解析数据,要打开浏览器,只能在有界面的系统使用,window下、带界面的Linux可以跑。
使用matchAllQuery搜索全部记录。
使用BoolQuery布尔查询组合matchQuery全文检索查询和TermQueryBuilder精准匹配查询 。
使用IK分词器ik_smart方式。
实现搜索高亮HighlightBuilder。
(2)建立ES索引。
使用默认shard,5个primary shard,5个replica shard。
title字段,使用IK分词器ik_smart解析,结合ES自带keyword分词器使用。
PUT /jd_goods { "mappings": { "properties": { "img": { "type": "keyword" }, "price": { "type": "double" }, "shopname": { "type": "keyword" }, "title": { "type": "text", "analyzer": "ik_smart", "fields": { "keyword": { "type": "keyword" } } }, "url": { "type": "keyword" } } } }3、freenom域名。
部署好了,绑定一个玉米,折腾了半天申请下来一个freenom免费玉米,配置好,因为没有备案,不到1分钟域名就被封了。。。。。。
4、部分代码。package com.xinxin.controller; import com.xinxin.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; import java.io.IOException; import java.util.List; import java.util.Map; @RestController public class ContentController { @Autowired private ContentService contentService; @GetMapping("/searchAll/{pageNo}/{pageSize}") public List
package com.xinxin.service; import com.alibaba.fastjson.JSON; import com.xinxin.pojo.Content; import com.xinxin.utils.ESconst; import com.xinxin.utils.HtmlParseUtil; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.text.Text; import org.elasticsearch.common.unit.Timevalue; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.query.*; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightField; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @Service public class ContentService { @Autowired private RestHighLevelClient restHighLevelClient; public Boolean parseContent(String keywords) throws Exception { Listcontents = new HtmlParseUtil().parseJD(keywords); //System.out.println(JSON.toJSonString(contents)); //把从网站查询到的数据放入ES中。 BulkRequest bulkRequest = new BulkRequest(); bulkRequest.timeout("2m"); for (int i = 0; i < contents.size(); i++) { bulkRequest.add( new IndexRequest(ESconst.ES_INDEX) .source(JSON.toJSonString(contents.get(i)), XContentType.JSON)); } BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT); return !bulk.hasFailures(); } public List > searchPage(String keyword, int pageNo, int pageSize) throws IOException { if (pageNo <= 1) { pageNo = 1; } //条件搜索 SearchRequest searchRequest = new SearchRequest(ESconst.ES_INDEX); //搜索源构建对象 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); //分页 sourceBuilder.from(pageNo); sourceBuilder.size(pageSize); //termQuery精准匹配 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); //解析结果 List > list = new ArrayList<>(); for (SearchHit hit : searchResponse.getHits().getHits()) { //hit.getSourceAsMap() 源文档内容,就是数据中_source中的内容 list.add(hit.getSourceAsMap()); } return list; } public List > searchPageHighlightBuilder(String keyword, int pageNo, int pageSize) throws IOException { if (pageNo <= 1) { pageNo = 1; } //条件搜索 SearchRequest searchRequest = new SearchRequest(ESconst.ES_INDEX); //搜索源构建对象 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); //分页 sourceBuilder.from(pageNo); sourceBuilder.size(pageSize); //termQuery精确匹配 TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword); sourceBuilder.query(termQueryBuilder); sourceBuilder.timeout(new Timevalue(60, TimeUnit.SECONDS)); //高亮,加上高亮。 HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.field("title"); highlightBuilder.preTags(""); highlightBuilder.postTags(""); //是否多个高亮显示 highlightBuilder.requireFieldMatch(false); sourceBuilder.highlighter(highlightBuilder); //执行搜索 searchRequest.source(sourceBuilder); SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); //解析结果 List > list = new ArrayList<>(); for (SearchHit hit : searchResponse.getHits().getHits()) { //解析出高亮,放到map中。 Map highlightFields = hit.getHighlightFields(); HighlightField title = highlightFields.get("title"); //源文档内容,就是数据中_source中的内容 //原来的结果。 Map 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; } public List > searchAllBuilder(int pageNo, int pageSize) throws IOException { //搜索请求对象 SearchRequest searchRequest = new SearchRequest(ESconst.ES_INDEX); //搜索源构建对象 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); //分页查询,设置起始下标,从0开始 searchSourceBuilder.from(pageNo); //每页显示个数 searchSourceBuilder.size(pageSize); //搜索方式 //matchAllQuery:搜索全部 searchSourceBuilder.query(QueryBuilders.matchAllQuery()); //source源字段过虑,第一个参数结果集包括哪些字段,第二个参数表示结果集不包括哪些字段 "title", "img", "price", "url", "shopname" searchSourceBuilder.fetchSource(new String[]{"title", "img", "price", "url", "shopname"}, new String[]{}); //向搜索请求对象中添加搜索源 searchRequest.source(searchSourceBuilder); //执行搜索,向es发出http请求 SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); //解析结果 List > list = new ArrayList<>(); for (SearchHit documentFields : searchResponse.getHits().getHits()) { list.add(documentFields.getSourceAsMap()); } return list; } public List > searchPageById(String id) throws IOException { //条件搜索 SearchRequest searchRequest = new SearchRequest(ESconst.ES_INDEX); //搜索源构建对象 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); //termsQuery精准匹配,根据id查询。 //String[] split = new String[]{"1","2"}; //List idList = Arrays.asList(split); TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery("_id", id); sourceBuilder.query(termsQueryBuilder); sourceBuilder.timeout(new Timevalue(60, TimeUnit.SECONDS)); //执行搜索 searchRequest.source(sourceBuilder); SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); //解析结果 List > list = new ArrayList<>(); for (SearchHit hit : searchResponse.getHits().getHits()) { //hit.getSourceAsMap() 源文档内容,就是数据中_source中的内容 list.add(hit.getSourceAsMap()); } return list; } public List > searchMatchQueryHighlight(String keyword, int pageNo, int pageSize) throws IOException { if (pageNo <= 1) { pageNo = 1; } //条件搜索 SearchRequest searchRequest = new SearchRequest(ESconst.ES_INDEX); //搜索源构建对象 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); //分页 sourceBuilder.from(pageNo); sourceBuilder.size(pageSize); //matchQuery即全文检索。它的搜索方式是先将搜索字符串分词,再使用各各词条从索引中搜索。 MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title", keyword).minimumShouldMatch("80%"); //80%相似度就能匹配到 sourceBuilder.query(matchQueryBuilder); sourceBuilder.timeout(new Timevalue(60, TimeUnit.SECONDS)); //高亮,加上高亮。 HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.field("title"); highlightBuilder.preTags(""); highlightBuilder.postTags(""); //是否多个高亮显示 highlightBuilder.requireFieldMatch(false); sourceBuilder.highlighter(highlightBuilder); //执行搜索 searchRequest.source(sourceBuilder); SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); //解析结果 List > list = new ArrayList<>(); for (SearchHit hit : searchResponse.getHits().getHits()) { //解析出高亮,放到map中。 Map highlightFields = hit.getHighlightFields(); HighlightField title = highlightFields.get("title"); //源文档内容,就是数据中_source中的内容 //原来的结果。 Map 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; } public List > searchMultiMatchQueryBuilder(String keyword, int pageNo, int pageSize) throws IOException { if (pageNo <= 1) { pageNo = 1; } //条件搜索 SearchRequest searchRequest = new SearchRequest(ESconst.ES_INDEX); //搜索源构建对象 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); //分页 sourceBuilder.from(pageNo); sourceBuilder.size(pageSize); //multiQuery多字段匹配查询,一次可以匹配多个字段。单项匹配是在一个field中去匹配,多项匹配是拿关键字去多个Field中匹配。 //keyword(注:xxx yyy中间需要有空格不然不分词)在title或者shopname中任何一个有就可以。 MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(keyword, "title", "shopname") .minimumShouldMatch("50%") //50%相似度就能匹配到 .field("title", 10);//提升boost:给name字段的权重提高10倍 sourceBuilder.query(multiMatchQueryBuilder); sourceBuilder.timeout(new Timevalue(60, TimeUnit.SECONDS)); //高亮,加上高亮。 HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.field("title"); highlightBuilder.preTags(""); highlightBuilder.postTags(""); //是否多个高亮显示 highlightBuilder.requireFieldMatch(false); sourceBuilder.highlighter(highlightBuilder); //执行搜索 searchRequest.source(sourceBuilder); SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); //解析结果 List > list = new ArrayList<>(); for (SearchHit hit : searchResponse.getHits().getHits()) { //解析出高亮,放到map中。 Map highlightFields = hit.getHighlightFields(); HighlightField title = highlightFields.get("title"); //源文档内容,就是数据中_source中的内容 //原来的结果。 Map 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; } public List > searchBoolQueryBuilder(String keyword, String shopname, int pageNo, int pageSize) throws IOException { if (pageNo <= 1) { pageNo = 1; } //条件搜索 SearchRequest searchRequest = new SearchRequest(ESconst.ES_INDEX); //搜索源构建对象 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); //分页 sourceBuilder.from(pageNo); sourceBuilder.size(pageSize); //BoolQuery布尔查询,搜索方式。 //1.先定义一个MultiMatchQuery,多字段匹配查询。 // multiQuery多字段匹配查询,一次可以匹配多个字段。单项匹配是在一个field中去匹配,多项匹配是拿关键字去多个Field中匹配。 // keyword(注:xxx yyy中间需要有空格不然不分词)在title或者shopname中任何一个有就可以。 MultiMatchQueryBuilder field = QueryBuilders.multiMatchQuery(keyword, "title", "price") .minimumShouldMatch("50%") //50%相似度就能匹配到 .field("title", 10);//提升boost:给name字段的权重提高10倍 //2.再定义一个termQuery,精准匹配查询。 TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title.keyword", keyword); //3.再定义一个BooleanQuery布尔查询,把上面两个查询结合在一起。 //BoolQuery布尔查询。 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); boolQueryBuilder.should(field); boolQueryBuilder.should(termQueryBuilder); sourceBuilder.query(boolQueryBuilder); sourceBuilder.timeout(new Timevalue(60, TimeUnit.SECONDS)); //高亮,加上高亮。 HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.field("title"); highlightBuilder.preTags(""); highlightBuilder.postTags(""); //是否多个高亮显示 highlightBuilder.requireFieldMatch(false); sourceBuilder.highlighter(highlightBuilder); //执行搜索 searchRequest.source(sourceBuilder); SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); //解析结果 List > list = new ArrayList<>(); for (SearchHit hit : searchResponse.getHits().getHits()) { //解析出高亮,放到map中。 Map highlightFields = hit.getHighlightFields(); HighlightField title = highlightFields.get("title"); //源文档内容,就是数据中_source中的内容 //原来的结果。 Map 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; } public List > searchBoolQueryBuilder2(String keyword, int pageNo, int pageSize) throws IOException { if (pageNo <= 1) { pageNo = 1; } //条件搜索 SearchRequest searchRequest = new SearchRequest(ESconst.ES_INDEX); //搜索源构建对象 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); //分页 sourceBuilder.from(pageNo); sourceBuilder.size(pageSize); //BoolQuery布尔查询,搜索方式。 //1.先定义一个MultiMatchQuery,多字段匹配查询。 // multiQuery多字段匹配查询,一次可以匹配多个字段。单项匹配是在一个field中去匹配,多项匹配是拿关键字去多个Field中匹配。 // keyword(注:spring css中间需要有空格不然不分词)在title或者shopname中任何一个有就可以。 MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title", keyword).minimumShouldMatch("80%"); //80%相似度就能匹配到 matchQueryBuilder.analyzer("ik_smart"); //matchQueryBuilder.analyzer("comma"); //2.再定义一个termQuery,精准匹配查询。 TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title.keyword", keyword); //MatchQueryBuilder matchQueryBuilder1 = QueryBuilders.matchQuery("title", keyword); //matchQueryBuilder1.analyzer("keyword"); //3.再定义一个BooleanQuery布尔查询,把上面两个查询结合在一起。 //BoolQuery布尔查询。 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); boolQueryBuilder.should(termQueryBuilder); boolQueryBuilder.should(matchQueryBuilder); sourceBuilder.query(boolQueryBuilder); sourceBuilder.timeout(new Timevalue(60, TimeUnit.SECONDS)); //高亮,加上高亮。 HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.field("title"); highlightBuilder.preTags(""); highlightBuilder.postTags(""); //是否多个高亮显示 highlightBuilder.requireFieldMatch(false); sourceBuilder.highlighter(highlightBuilder); //执行搜索 searchRequest.source(sourceBuilder); SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); //解析结果 List > list = new ArrayList<>(); for (SearchHit hit : searchResponse.getHits().getHits()) { //解析出高亮,放到map中。 Map highlightFields = hit.getHighlightFields(); HighlightField title = highlightFields.get("title"); //源文档内容,就是数据中_source中的内容 //原来的结果。 Map 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; } public List > searchBoolFilterQueryBuilder(String keyword, int pageNo, int pageSize) throws IOException { if (pageNo <= 1) { pageNo = 1; } //条件搜索 SearchRequest searchRequest = new SearchRequest(ESconst.ES_INDEX); //搜索源构建对象 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); //分页 sourceBuilder.from(pageNo); sourceBuilder.size(pageSize); //BoolQuery布尔查询,搜索方式。 //1.先定义一个MultiMatchQuery,多字段匹配查询。 // multiQuery多字段匹配查询,一次可以匹配多个字段。单项匹配是在一个field中去匹配,多项匹配是拿关键字去多个Field中匹配。 // keyword(注:spring css中间需要有空格不然不分词)在title或者shopname中任何一个有就可以。 MultiMatchQueryBuilder field = QueryBuilders.multiMatchQuery(keyword, "title", "shopname") .minimumShouldMatch("50%") //50%相似度就能匹配到 .field("title", 10);//提升boost:给name字段的权重提高10倍 //2.再定义一个BooleanQuery布尔查询。 //BoolQuery布尔查询。 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); boolQueryBuilder.must(field); //过虑是针对搜索的结果进行过虑,过虑器主要判断的是文档是否匹配,不去计算和判断文档的匹配度得分, // 所以过虑器性能比查询要高,且方便缓存,推荐尽量使用过虑器去实现查询或者过虑器和查询共同使用。 //过滤器,过滤条件。 //boolQueryBuilder.filter(QueryBuilders.termQuery("publish", "201001"));//在publish里过滤201001 boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(60).lte(100)); //价格区间 sourceBuilder.query(boolQueryBuilder); sourceBuilder.timeout(new Timevalue(60, TimeUnit.SECONDS)); //高亮,加上高亮。 HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.field("title"); highlightBuilder.preTags(""); highlightBuilder.postTags(""); //是否多个高亮显示 highlightBuilder.requireFieldMatch(false); sourceBuilder.highlighter(highlightBuilder); //执行搜索 searchRequest.source(sourceBuilder); SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); //解析结果 List > list = new ArrayList<>(); for (SearchHit hit : searchResponse.getHits().getHits()) { //解析出高亮,放到map中。 Map highlightFields = hit.getHighlightFields(); HighlightField title = highlightFields.get("title"); //源文档内容,就是数据中_source中的内容 //原来的结果。 Map 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; } public List > search(String keyword, int pageNo, int pageSize) throws Exception { List > list = searchBoolQueryBuilder2(keyword, pageNo, pageSize); if (list.size()==0 || list.isEmpty()) { Boolean bool = parseContent(keyword); if (bool) { while (list.size()==0) { list = searchBoolQueryBuilder2(keyword, pageNo, pageSize); } } } return list; } }
package com.xinxin.utils; import com.xinxin.pojo.Content; import org.jsoup.Jsoup; import org.jsoup.nodes.document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import org.openqa.selenium.Platform; import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxBinary; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.firefox.FirefoxProfile; import org.springframework.util.StringUtils; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; public class HtmlParseUtil { public static void main(String[] args) throws Exception { new HtmlParseUtil().parseJD("java").forEach(System.out::println); } public ListparseJD(String keywords) throws IOException, InterruptedException { //获取请求 https://search.jd.com/Search?keyword=java&enc=utf-8 String requestURL = "https://search.jd.com/Search?enc=utf-8&keyword=" + keywords; //方式一:等待网页加载完成解析。 //版本:firefox浏览器:91.3.0esr (64 位)。geckodriver.exe:v0.30.0。 //1、安装firefox浏览器。 //2、下载geckodriver.exe驱动。下载地址:https://github.com/mozilla/geckodriver/releases,根据系统情况下载对于的驱动。例如:下window的驱动geckodriver-v0.30.0-win64.zip。 //3、解压geckodriver-v0.30.0-win64.zip,将geckodriver.exe放到firefox安装目录,例如:D:Program FilesMozilla Firefox //方式二:不等网页加载完成就解析,解析网页,jsoup返回document就是浏览器document对象。 document document = Jsoup.parse(new URL(requestURL), 30000); //System.out.println(document.html()); Element element = document.getElementById("J_goodsList"); //System.out.println(element.html()); //获取所有的li元素 Elements elements = element.getElementsByTag("li"); List goodsList = new ArrayList<>(); Content content = null; //获取元素中的内容。 for (Element el : elements) { //获取图片,第1个img标签的src属性。 String img = el.getElementsByTag("img").eq(0).attr("data-lazy-img"); if ("done".equals(img) || StringUtils.isEmpty(img)) { img = el.getElementsByTag("img").eq(0).attr("src"); } if ("done".equals(img) || StringUtils.isEmpty(img)) { img = el.getElementsByTag("img").eq(0).attr("source-data-lazy-img"); } //获取价格,获取p-price样式的div的文本。 //System.out.println(el.getElementsByClass("p-price").eq(0).select("strong").text()); String price = el.getElementsByClass("p-price").eq(0).select("strong").text(); price = price.replaceFirst("¥", ""); //获取标题,获取p-name样式的div的文本。 String title = el.getElementsByClass("p-name").eq(0).select("em").text(); //获取详情页地址 String url = el.getElementsByTag("a").eq(0).attr("href"); //店铺名称 String shopname = el.getElementsByClass("hd-shopname").eq(0).text(); System.out.println("====================================="); System.out.println(img); System.out.println(price); System.out.println(title); System.out.println(url); System.out.println(shopname); content = new Content(); content.setTitle(title); Double price1 = StringUtils.isEmpty(price) ? 6.66d : Double.parseDouble(price); content.setPrice(price1); content.setImg(img); content.setUrl(url); content.setShopname(shopname); goodsList.add(content); } return goodsList; } }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)