前言
根据URL解析HTML获取文件URL并下载存储
最近公司接入了一个平台的数据,给了一个连接,存放每天定时推的文件列表。我这里需要做的就是我要把这些文件下载下来,保存到服务器上,其他人那它去用。
正文
一、URL内容
提供的URL使用用户名和密码登录进去长这个样子。这个是<body></body>
部分,我主要处理这个部分。
事实上他这个标签实在是不规律。只有后面的文件名使用<a></a>
包括。所以只能对这个做文章。
二、需求
每次定时访问这个URL,需要下载自己服务器上的存放位置没有的最新文件,那么需要一个记录值来记录最后下载的一个位置。
当是首次下载,那么没有这个记录值的时候,我只需要下载最新文件中后缀是“f”的压缩包,然后记录这个值。
当是后续下载,需要根据记录值下载它后面的所有文件,然后记录这个值。
二、使用步骤
1.引入库
URL访问和解析使用dom4j的相关东西。
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.49</version>
</dependency>
2.贴代码(长代码警告)
public class FileUtils {
private static final Logger logger = LoggerFactory.getLogger(DowJonesFileUtils.class);
private static InputStream inputStream;
private static BufferedInputStream bi;
private static HttpURLConnection conn;
private static URL httpUrl;
private static OutputStream outputStream;
private static BufferedOutputStream bo;
//需要登录的网站
private static String baseURL = "https://*******.com";
//记录值文件
private static String recordFile = "record.txt";
//文件存放位置
private static String dirPath = "/data/******";
//定时任务每四个小时执行一次
@Scheduled(cron = "0 0/4 * * * ?")
public void operate() throws IOException {
logger.info("文件下载开始");
//登录
FileUtils jones = new FileUtils();
Connection.Response login = jones.login();
logger.info("登录成功");
//解析
Elements pre_a = jones.parse(login);
if (pre_a ==null){
return;
}
//获取记录的文件信息,确定下载位置
File file = new File(dirPath+"/"+recordFile);
//把记录位置以后的文件,作为要下载的文件,集合
List<String> downURL = jones.getDownURL(pre_a, file);
if (downURL.size()==0){
logger.info("没有需要下载的文件");
logger.info("文件下载结束");
return;
}
logger.info("开始下载,剩余文件数量:"+downURL.size());
//下载文件
downFile(downURL);
logger.info("文件下载结束");
}
/**
* @Description: 登录
* @param
* @return org.jsoup.Connection.Response
* @throws
* @author Surpass
* @date 2020/10/15 11:11
*/
private Connection.Response login(){
Connection.Response login = null;
try {
login = Jsoup.connect("https://***********/XML/1815")
.data("Username","****") //账号
.data("Password","********") //密码
.header("Authorization","*******") //url网站访问权限 请求头里
.method(Connection.Method.GET)
.execute();
} catch (IOException e) {
logger.info("登录异常:",e);
}
return login;
}
/**
* @Description: 登录解析html获取文件主体
* @param login
* @return org.jsoup.select.Elements
* @throws
* @author Surpass
* @date 2020/10/15 11:09
*/
private Elements parse(Connection.Response login){
Document document = null;
if (login ==null){
return null;
}
try {
document = login.parse();
} catch (IOException e) {
logger.info("解析异常:",e);
}
//根据html代码选择获取了所有的链接标签
Elements pre_a = document.select("pre a");
return pre_a;
}
/**
* @Description: 根据标签ELe获取需要加载的URL
* @param pre_a, 标签ELes
* baseURL, url前缀
* file 记录文件
* @return java.util.List<java.lang.String>
* @throws
* @author Surpass
* @date 2020/10/14 18:40
*/
private List<String> getDownURL(Elements pre_a,File file) throws IOException {
//获取记录文件中的记录时间和全、增量标识
Double recordData = null;
char recordType = 0;
String record = null;
if (!file.exists()){
file.createNewFile();
}else {
//获取记录文件中的记录值
Reader reader = new FileReader(file);
BufferedReader br = new BufferedReader(reader);
record = br.readLine();
if (record!=null&&record.trim()!=""){
String[] split = record.split("_");
recordData = Double.valueOf(split[0]);
recordType = split[1].charAt(0);
}
if (br!=null){
br.close();
}
if (reader!=null){
reader.close();
}
}
ArrayList<String> list = new ArrayList<>();
//标签中的text
List<String> textList = pre_a.eachText();
//标签中的属性
List<String> hrefList = pre_a.eachAttr("href");
//获取记录值之后的文件URL,存入集合
for (int i = 0; i < hrefList.size(); i++) {
String href = hrefList.get(i);
String downURL = baseURL+href;
String text = textList.get(i);
//URL过滤
if (!text.endsWith(".zip")){
continue;
}
//当有记录值的时候,下载记录值以后的所有文件
if (StringUtils.isNotBlank(record)){
String[] textArr = text.split("_");
Double fileData = Double.valueOf(textArr[4]);
//当前值和记录值相同
if (fileData.equals(recordData)){
if ( recordType=='f' && textArr[5].charAt(0)=='i' ){
list.add(downURL);
}
}
if (fileData>recordData){
list.add(downURL);
}
}
//当没有记录值的时候,只下载最新的全量(当倒数第二个是全量,那么直接跳出循环)
if (StringUtils.isBlank(record)){
char flag = textList.get(i).charAt(textList.get(i).length() - 5);
if (i==hrefList.size()-2&&flag=='f'){
list.add(downURL);
break;
}
if (i==hrefList.size()-1&&flag=='f'){
list.add(downURL);
}
}
}
logger.info("需要下载的URL数量:"+list.size());
return list;
}
/**
* @Description: 这里是重点了,拿到了需要获取的URL,请求下载并保存
* @param downURL, 需要下载的文件url
* dirPath, 保存文件路径
* recordPath 记录文件的位置
* @return void
* @throws
* @author Surpass
* @date 2020/10/15 11:09
*/
private void downFile(List<String> downURL) {
int urlFlag = 0;
try {
for (String url : downURL) {
//文件下载登录
httpUrl=new URL(url);
conn=(HttpURLConnection) httpUrl.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Authorization","*******");
conn.connect();
logger.info(url+":连接成功");
//获取输入流
inputStream = conn.getInputStream();
bi = new BufferedInputStream(inputStream);
String fileName = url.substring(url.lastIndexOf("/"));
//获取输出流
outputStream = new FileOutputStream(dirPath+fileName);
bo = new BufferedOutputStream(outputStream);
byte[] bytes = new byte[1024*10];
int len = 0;
while ( (len = bi.read(bytes))!=-1){
bo.write(bytes,0,len);
}
logger.info("上传URL文件到服务器成功:"+url);
//记录当前下载位置
String record = url.substring(69, 83);
Writer recordWriter = new FileWriter(dirPath+"/"+recordFile);
BufferedWriter recordBf = new BufferedWriter(recordWriter);
recordBf.write(record);
logger.info("上传记录文件record.txt成功");
//关闭
recordBf.flush();
recordBf.close();
recordWriter.close();
++urlFlag;
logger.info("下载完成,剩余文件数量:"+(downURL.size()-urlFlag));
}
}catch (Exception e){
logger.info("下载失败",e);
}finally {
//关闭流
try {
if (bo!=null){
bo.flush();
bo.close();
}
if (inputStream!=null){
inputStream.close();
}
if (bi!=null){
bi.close();
}
if (outputStream!=null){
outputStream.close();
}
if (conn!=null){
conn.disconnect();
}
} catch (IOException e) {
logger.info("输入流关闭异常",e);
}
}
}
}
3.下载的文件
总结
这一次这个任务结合了网页的解析,用Java下载文件,输入输出流等一些东西,本来文件是存放在sftp服务器的,后来需求改了。这是第一次在项目中使用网页解析,博主会在代码中加很多注释。这里记录下,可作为参考。
当然,代码还存在很多需要完善的地方,还请各位大佬指出不足,后续加倍努力。