文章已同步到个人博客:http://www.tianshaojiao.com/?p=337
工欲善其事必先利其器,首先介绍一下这次我用到的工具:Jsoup。那么jsoup是何方神圣呢?下面是我在网上找到的对它的定义:
jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。
有了它,我们就可以很轻松的获取某个web页面的DOM文档,并利用jsoup强大的html解析功能,获取dom文档里面包含的我们需要的信息;在这次代码编写中,我的项目架构是:SpringBoot 、Mybatis、Mysql、fastdfs、Jsoup;先来看看效果吧:
本地文件:
数据库结果:
爬取文件是的主要步骤:
- 打开目标网页
- 按F12查看我们需要的数据所在的容器Dom元素,找到该元素的关键属性,例如:id,唯一的class,唯一的属性等,总之是能在整个页面中唯一标识它的属性
- 编写代码,获取目标网页的DOM文档
- 使用JSoup解析Dom文档,取得数据元素
- 转存目标数据
下面是封装Jsoup的方法:
package com.mrajoe.webapp.cloudoauth.util;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author : tianshaojiao
* @version : 1.0
* @apiNote :
* @date : 2019/12/20
* @copyright :
*/
public class JSoupUtils {
/** 格式化字符串,使之能成为一个合法的文件夹或文件名称格式*/
private static Pattern pattern = Pattern.compile("[\\s\\\\/:\\*\\?\\\"<>\\|]");
/** 取得连接*/
public static Connection getConnection(String url, Map<String,String> headers){
Connection connection = null;
int retryCount = Integer.parseInt("6");
int currentRetryCount = 0;
while (currentRetryCount < retryCount){
try {
connection = Jsoup.connect(url);
break;
} catch (Exception e) {
currentRetryCount++;
}
}
return connection;
}
/** 取得Html文档*/
public static Document getDocument(Connection connection, Map<String,String> headers){
Document document = null;
if (null != connection){
int retryCount = Integer.parseInt("6");
int currentRetryCount = 0;
while (currentRetryCount < retryCount){
try {
document = connection.data(headers).get();
break;
} catch (Exception e) {
currentRetryCount++;
}
}
}
return document;
}
/** 格式化字符串*/
public static String getLegalFileName(String fileName){
Matcher matcher = pattern.matcher(fileName);
return matcher.replaceAll("");
}
/** 主方法*/
public static void main(String[] args) {
String targetUrl = "";
Map<String,String> headers = new HashMap<>();
Document doc = JSoupUtils.getDocument(JSoupUtils.getConnection(targetUrl, headers), headers);
}
}
下面是将目标网站上的文件下载到本地,并上传到自己的文件服务器的关键代码
private synchronized String getAlbumRemoteBgUrl(String albumIn5kmmBgUrl,Map<String,String> headers,String token) throws Exception{
log.info("开始将远程地址["+albumIn5kmmBgUrl+"]转存到mrajoe的服务器!");
//取得文件下载请求头信息
URL url = new URL(albumIn5kmmBgUrl);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
//设置超时间为3秒
conn.setConnectTimeout(10*60*1000);
//防止屏蔽程序抓取而返回403错误
for(Map.Entry<String,String> entry:headers.entrySet()){
conn.setRequestProperty(entry.getKey(), entry.getValue());
}
//得到输入流
InputStream inputStream = conn.getInputStream();
File tempDir = new File(fileDownloadTempPath);
if (!tempDir.exists()){
tempDir.mkdirs();
}
String fileSavePath = fileDownloadTempPath + File.separator
+ UniqueId.getUniqueId() + albumIn5kmmBgUrl.substring(albumIn5kmmBgUrl.lastIndexOf("."),albumIn5kmmBgUrl.length());
File tempFile = new File(fileSavePath);
FileOutputStream foos = new FileOutputStream(tempFile);
int len = 0;
while ((len = inputStream.read()) != -1){
foos.write((byte)len);
}
foos.close();
inputStream.close();
log.info("文件["+albumIn5kmmBgUrl+"]下载完毕!!");
//上传文件
Map<String,String> mrajoeUploadHeaders = new HashMap<String,String >();
mrajoeUploadHeaders.put("authToken",token);
List<File> files = new ArrayList<File>();
files.add(new File(fileSavePath));
String fileUrl = "";
try {
String uploadResult = HttpClientUtils.uploadFile(imageUploadUrl,null,mrajoeUploadHeaders,files,null);
JSONObject jsonUploadResult = JSONObject.parseObject(uploadResult);
if ("200".equalsIgnoreCase(jsonUploadResult.getString("statusCode"))){
fileUrl = jsonUploadResult.getString("fileUrl");
} else {
fileUrl = albumIn5kmmBgUrl;
}
log.info("mrajoe文件服务器:文件上传成功,地址:"+fileUrl);
} catch (Exception e) {
log.info("上传文件到远程服务器异常",e);
}
return fileUrl;
}
取得请求头信息的方法:
private Map<String,String> getHeaders(){
Map<String,String> headers = new HashMap<String, String>();
headers.put("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3");
headers.put("Accept-Encoding","gzip, deflate");
headers.put("Accept-Language","en,zh-CN;q=0.9,zh;q=0.8");
headers.put("Connection","keep-alive");
headers.put("Cookie","UM_distinctid=16f1d597f8e182-072f0d2d77ec82-5373e62-144000-16f1d597f8f684; bdshare_firstime=1576745531077; Hm_lvt_bd6c96323a627eebbe50e420ba111ab1=1576748305,1576812191,1576812209,1577065725; CNZZDATA1256540375=1791569634-1576743066-https%253A%252F%252Fwww.baidu.com%252F%7C1577081490; Hm_lpvt_bd6c96323a627eebbe50e420ba111ab1=1577082143");
headers.put("Host",观察目标网站获取);
headers.put("Referer",观察目标网站获取);
headers.put("Upgrade-Insecure-Requests","1");
headers.put("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36");
return headers;
}