通过三个简单的案例,来实现的,都是不加验证的情况下. 如果有拼图验证网上也有对应的实现方法自行查找即可. 这里仅仅是一个简单的Demo, 练习使用
0. 爬取网站的配置:
article:config:#中央新闻网-三农头条数据部分ntvUrl: https://www.ntv.cn/# 全国农技推广网- 农技动态部分nongJi: https://www.natesc.org.cn/dtxx/index?CategoryId=959cd01c-e9fa-43d9-a04b-48317bdc3794# 农技网基础路径nongJiBaseUrl: https://www.natesc.org.cn# 中国农网-热点推荐数据farmerUrl: https://www.farmer.com.cn/
1. 依赖导入
<!-- 作用是把html界面封装为一个Document对象 类似于Python的 Beautiful Soup -->
<dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.13.1</version>
</dependency>
<!-- 这个是处理未进行界面渲染的问题, 比如农机网的全国农技推广网-农技动态部分通过HTTPClient获取的就是未渲染的 -->
<dependency><groupId>net.sourceforge.htmlunit</groupId><artifactId>htmlunit</artifactId><version>2.43.0</version>
</dependency>
<!-- 上面依赖这个jar包 -->
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.11.0</version>
</dependency>
2. 配置类
package com.saas.prod.common;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;/*** @author : Cookie* date : 2023/11/15*/
@Component
@Data
// prefix 中的配置只能是小写,否则编译过不去好像
@ConfigurationProperties(prefix = "article.config")
public class ArticleMessageConfig {/*** 中央新闻网 三农头条数据url*/private String ntvUrl;/*** 农技中心动态*/private String nongJi;/*** 农技基础url*/private String nongJiBaseUrl;/*** 中国农网url*/private String farmerUrl;
}
中央新闻网-三农动态部分
@Overridepublic void insertNtvData() {String url = messageConfig.getNtvUrl();String html = HttpClientUtil.doGetForHTML(url);Document document = Jsoup.parse(html);Elements elements = document.getElementsByClass("question_rank");Elements aElements = elements.get(0).select("a");for (Element aElement : aElements) {String href = aElement.attr("href");String title = aElement.getElementsByTag("p").attr("title");ArticleMessage build = ArticleMessage.builder().title(title).insertTime(LocalDateTime.now()).build();if (getHref(href, build))break;}}/*** 三农头条数据填充** @param url 路径* @param build 对象*/private boolean getHref(String url, ArticleMessage build) {String html = HttpClientUtil.doGetForHTML(url);Document document = Jsoup.parse(html);Elements article = document.select("div.art_con");Elements select = document.select("p.mb10");String source = select.select("span").get(0).text();String createTime = select.select("span").get(1).text();build.setSource(source);build.setTime(createTime.split(" ")[0]);build.setArticle(article.toString().replace("<div class=\"art_con\">", "<div id=\"content\">"));String todayStartStr = getTodayStartStr();// 如果是当天的新闻再插入到数据库,因为旧数据都已经插入了也就没有必要执行了if (todayStartStr.compareTo(build.getTime()) <= 0) {if (0 == articleMessageMapper.selectByTitle(build.getTitle()))articleMessageMapper.insert(build);} else {// 说明剩余的数据都是旧数据,就不在操作直接返回return true;}return false;}
中国农网-热点推荐数据
@Overridepublic void insertFarmerData() {Document parse = Jsoup.parse(HttpClientUtil.doGetForHTML(messageConfig.getFarmerUrl()));Elements elements = parse.getElementsByClass("area-center w-486");Elements a = elements.select("a");for (Element element : a) {String href = element.attr("href");String title = element.text();ArticleMessage build = ArticleMessage.builder().title(title).build();if (setMessageForFarmer(href, build))break;}}/*** 中国农网获取数据填充** @param href 链接* @param build 数据对象*/private boolean setMessageForFarmer(String href, ArticleMessage build) {try {Document parse = Jsoup.parse(HttpClientUtil.doGetForHTML(href));Elements elementsByClass = parse.getElementsByClass("index-introduce");Elements elements = elementsByClass.select("li");String source = elements.first().select("span").text();String date = elementsByClass.select("ul").first().select("div").first().select("span").text();Elements article = parse.getElementsByClass("textList");build.setSource(source);build.setTime(date.split(" ")[0]);build.setInsertTime(LocalDateTime.now());build.setArticle(article.toString().replace("<div class=\"textList\">", "<div id=\"content\">"));String todayStartStr = getTodayStartStr();// 如果是当天的新闻再插入到数据库,因为旧数据都已经插入了也就没有必要执行了if (todayStartStr.compareTo(build.getTime()) <= 0) {if (0 == articleMessageMapper.selectByTitle(build.getTitle()))articleMessageMapper.insert(build);} else {return true;}} catch (Exception e) {// 这里有异常的及时提醒我查找问题 MailUtils.sendMail("yfs1024@163.com", "数据插入异常", "路径:" + href);log.error("数据插入异常:{},路径{}", e.getMessage(), href);return true;}return false;}
全国农技推广网- 农技动态部分
@Overridepublic void insertNongJiData() {Document document1 = getParsedDocument(messageConfig.getNongJi());if (document1 == null)return;Element newsUl = document1.getElementById("newsUl");Elements elements = newsUl.select("a");for (Element element : elements) {String href = element.attr("href");String title = element.attr("title");String finalUrl = messageConfig.getNongJiBaseUrl() + href;ArticleMessage build = ArticleMessage.builder().title(title).build();// 填充其他数据if (setMessageForNongji(build, finalUrl))break;}}/*** 填充农技动态中心数据** @param build 对象* @param finalUrl 路径*/private boolean setMessageForNongji(ArticleMessage build, String finalUrl) {try {Document parsedDocument = getParsedDocument(finalUrl);if (parsedDocument == null)return true;Element newsTime = parsedDocument.getElementById("newsTime");Elements elements = newsTime.getElementsByClass("span1");String date = elements.first().getElementsByClass("span2").text();String source = elements.get(1).getElementsByClass("span2").text();Element content = parsedDocument.getElementById("content");String finalContent = content.toString().replace("src=\"", "src=\"" + messageConfig.getNongJiBaseUrl());build.setTime(date);build.setSource(source);build.setInsertTime(LocalDateTime.now());// 填充文本数据包括图片build.setArticle(finalContent);String todayStartStr = getTodayStartStr();// 插入当天的if (todayStartStr.compareTo(date) <= 0) {if (0 == articleMessageMapper.selectByTitle(build.getTitle()))articleMessageMapper.insert(build);} else {// 说明剩余的数据都是旧数据,就不在操作直接返回return true;}} catch (Exception e) {MailUtils.sendMail("yfs1024@163.com", "数据插入异常", "路径:" + finalUrl);log.error("数据插入异常:{},路径{}", e.getMessage(), finalUrl);}return false;}
示例HTML:
<div class="index-introduce"><ul><li>来源:<span>中国农网</span></li><li>编辑:<span>暴佳然</span></li><li>作者:<span>杨志华</span></li><div><span>2023-11-17 08:45:11</span></div></ul><div class="fontSize"><img class="add" src="https://www.farmer.com.cn//Public/newNongWang/images/字体变大.png?time=657" alt=""><img class="sub" src="https://www.farmer.com.cn//Public/newNongWang/images/字体减小.png?time=277" alt=""></div>
</div>
Document parse = Jsoup.parse(HttpClientUtil.doGetForHTML(href));
// 通过class获取节点
Elements elementsByClass = parse.getElementsByClass("index-introduce");
// 获取节点中所有的li标签数据
Elements elements = elementsByClass.select("li");
// 获取第一个li中的span标签中的文本内容 也就是这里的: 中国农网
String source = elements.first().select("span").text();
// 获取ul标签,再获取ul中的div获取span中的文本
String date = elementsByClass.select("ul").first().select("div").first().select("span").text();
方法总结:
获取标签的常用方法
getElementsByClass
// 通过class定位
Elements elementsByClass = parse.getElementsByClass("index-introduce");
getElementsById
// 通过id定位
Element newsTime = parsedDocument.getElementById("newsTime");
select
这里方法有很多选择方式,详细在最下面的链接中
通过Element对象获取对应的标签
getElementsByTag
通过标签获取
String title = aElement.getElementsByTag("p").attr("title");
获取属性常用方法
attr
String href = element.attr("href");
String title = element.attr("title");
总结:
- 通过HttpClient获取到界面的html
- 通过JSoup进行解析, 获得一个Document对象
- 通过方法一层一层的获取到其中的数据,或者属性
其他的常用方法链接:
jsoup使用指南