本文主要介绍了一款非常好用的基于Java语言的爬虫工具,并实现将网页数据自动导出Excel的功能
一、利用爬虫工具爬取网页数据
JSoup是一个用于解析、操作和提取HTML和XML文档数据的Java库。它主要用于Web抓取,特别是在需要从网页中提取数据、进行数据挖掘或网页分析时非常有用。它提供了简单而强大的API,使得在Java中进行网页爬取和数据提取变得更加容易。以下是JSoup的一些主要特性和用法:
(一) Jsoup 主要特性:
1. 解析HTML和XML:
JSoup能够解析HTML和XML文档,支持从URL、文件、字符串等不同来源加载文档。
2. DOM操作:
JSoup提供了类似于JavaScript中的DOM操作方式,可以轻松地遍历文档树、选择特定的元素或节点,并进行增删改查操作。
3. CSS选择器:
类似于jQuery,JSoup支持使用CSS选择器来定位和选取文档中的元素,方便快捷地提取目标数据。
4. 清理和转换HTML:
JSoup能够处理不规范的HTML,可以清理文档、格式化输出或将HTML转换为纯文本。
5. HTTP请求:
虽然主要是HTML解析库,但JSoup也可以用来发送HTTP请求并获取网页内容,方便进行网页抓取。
6. 安全性考虑:
JSoup能够防范跨站脚本攻击(XSS),它提供了API来清理用户提供的HTML内容,以保护应用程序免受恶意攻击。
(二)利用Jsoup爬取网页数据
1. pom文件导入依赖
首先新建一个空的springboot工程项目,然后导入爬虫工具Jsoup所需要的依赖包,再进行maven构建。
// Jsoup依赖包
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.14.3</version>
</dependency>
2. 爬虫核心代码
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
public class JsoupExample {
public static void main(String[] args) {
try {
String url = "网址URL";
// 发送HTTP GET请求并获取网页内容
Document document = (Document) Jsoup.connect(url).get();
// 获取网页标题
String title = document.title();
System.out.println("网页标题:" + title);
System.out.println("-----------------------------------------------");
// 获取网页内带有“a[href]”标签的内容
Elements links = document.select("a[href]");
System.out.println("链接数量:" + links.size());
// 打印每个链接的文本和URL
for (Element link : links) {
//获取HTML元素<a>中的文本内容
String linkText = link.text();
//获取HTML元素<a>中href属性的值
String linkUrl = link.attr("href");
System.out.println("链接文本:" + linkText);
System.out.println("链接URL:" + linkUrl);
}
// 获取网页内带有“td”标签的的内容
Elements contents = document.select("td");
System.out.println("内容数量:" + contents.size());
System.out.println("-----------------------------------------------");
// 数据整理(自定义的方法,根据自己的实际情况编写)
Map<String, String> collatedData = DataCollation.dataCollation(contents);
// 打印整理后的数据
for (Map.Entry<String, String> entry : collatedData.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
} catch (IOException e) {
e.printStackTrace();
}
}
3. 常见问题解决
在进行网页数据爬取的时候,还可能会出现下面的报错问题:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1514)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:961)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:153)
at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:859)
at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:829)
at org.jsoup.helper.HttpConnection.execute(HttpConnection.java:366)
at org.jsoup.helper.HttpConnection.get(HttpConnection.java:353)
at org.example.utils.JsoupExample.main(JsoupExample.java:22)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1496)
... 15 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
... 21 more
问题分析
经过研究,发现这个错误其实是由于在与网页进行SSL/TLS 握手的过程中出现了证书问题导致的。可能是由于远程主机的 SSL 证书无法验证,或者本地 Java 证书存储中缺少必要的证书而导致的。在运行你的 Java 应用程序之前,需要将缺失的证书导入到 Java 证书存储中。
问题解决
a. 在谷歌浏览器中访问目标网站并点击网址链接旁边的符号,查看证书信息。
b. 导出目标网站的证书文件。
c. 在 Java 的证书存储中导入该证书。使用 keytool 命令完成此操作。
注意要在Java本地安装路径JDK文件夹的 bin文件夹路径下打开命令行窗口,因为这里才有keytool工具。
keytool导入指定证书
keytool -importcert -file 证书文件本地路径 -keystore JDK本地安装路径\jre\lib\security\cacerts -storepass changeit
参数解释:
keytool -importcert :keytool导入证书命令
-storepass:参数用于指定证书存储的密码。对于默认的 Java 证书存储(cacerts),默认密码为 changeit。
将SSL证书加入到Java证书存储库之后,再次运行代码就可以爬取网址指定信息了
二、网页数据自动导出Excel
爬取完所有数据之后,我们可以利用SpringBoot框架的基本操作,创建针对数据的实体类,然后将其存放到数据库表里,现在需要将数据库表中的数据导出成Excel。经过技术探索,最终选择了 Alibaba 的 EasyExcel 库,配合@ExcelProperty注解,简便高效!!
(一)pom文件导入依赖
<!-- easyExcel-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.1</version>
</dependency>
(二) 创建数据Vo类并添加@ExcelProperty注解
创建Vo类的目的就是为了更规范的显示数据库数据,这里加上==@ExcelProperty==注解,可以设置该属性导出成Excel之后的列名。这样一来,导出的Excel数据就可以自动添加列名。
(三)数据导出Excel的controller接口方法
/**
* 将数据导出Excel
* @param response
* @throws IOException
*/
@GetMapping("/exportExcel")
public void exportExcel(HttpServletResponse response) throws IOException {
// 数据vo列表,该Vo类的属性已经添加了@ExcelProperty注解
// 这里写了一个service方法,来获取数据库表中存入的所有爬取数据
List<PublicityReportVo> dataList = publicityReportService.getAllData();
// 设置响应头
String filename = "导出的文件名";
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename="+filename+".xlsx");
// 使用EasyExcel直接写入数据,自动映射刚才写的数据Vo类
// 它会自动处理列名,这里设置表单名为 Data
EasyExcel.write(response.getOutputStream(), PublicityReportVo.class)
.sheet("Data")
.doWrite(dataList);
}
这里需要特别注意的是,一定要设置响应头,因为这里可以指定输出的文件格式,如果不设置的话,输出的文件就可能会是zip格式的,会很奇怪!!
最后,启动controller服务,在网页中输入接口的访问地址,就可以在网页里自动下载,得到我们想要的Excel文件啦!!!!