问题:从指定网址上下载图片到本机。
要求:
- 通过解析页面,分析出指定图片,并且下载。注意:不是指定图片地址。
图片对应的网址:http://origin.cpc.ncep.noaa.gov/products/people/mchen/CFSv2FCST/monthly/ 要求,下载其中的SST这一列的全部图片。 - 下载前对图片是否已经存在要做判断。
提示:java解析网址用jsoup
1. 提前说明:本文使用maven完成,因为用到了Jsoup,pom文件中肯定要引啦。此外我还引入了log4j、slf4j-log4j12、commons-net。
口说无凭,pom.xml文件如下(dependencies部分)
<dependencies> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.7</version> </dependency> <dependency> <groupId>commons-net</groupId> <artifactId>commons-net</artifactId> <version>3.6</version> </dependency> <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.10.2</version> </dependency> </dependencies>
2. 全部引入后,配置log4j文件,将其放到 srcmain esources目录下,取名log4j.properties(没有引入log4j、slf4j-log4j12的此步忽略)
log4j.properties配置文件如下:
log4j.rootLogger=INFO,Console,File
#定义日志输出目的地为控制台
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.Target=System.out
#可以灵活地指定日志输出格式,下面一行是指定具体的格式
log4j.appender.Console.layout = org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm} %c] - %m%n
#文件大小到达指定尺寸的时候产生一个新的文件
log4j.appender.File = org.apache.log4j.RollingFileAppender
#指定输出目录
log4j.appender.File.File = logs/info.log
#定义文件最大大小
log4j.appender.File.MaxFileSize = 10MB
# 输出所有日志,如果换成DEBUG表示输出DEBUG以上级别日志
log4j.appender.File.Threshold = ALL
log4j.appender.File.layout = org.apache.log4j.PatternLayout
log4j.appender.File.layout.ConversionPattern =[%p] [%d{yyyy-MM-dd HH:mm:ss}][%c]%m%n
3. 开始撸码
1 package com.url; 2 3 import org.jsoup.Jsoup; 4 import org.jsoup.nodes.Document; 5 import org.jsoup.nodes.Element; 6 import org.jsoup.select.Elements; 7 import org.slf4j.Logger; 8 import org.slf4j.LoggerFactory; 9 10 import java.io.*; 11 import java.net.HttpURLConnection; 12 import java.net.MalformedURLException; 13 import java.net.URL; 14 import java.net.URLEncoder; 15 16 /** 17 * @author 清风明月 18 * @description 19 * @date 2019/7/14 14:08 20 */ 21 public class ParseUrl { 22 private static final Logger logger = LoggerFactory.getLogger(ParseUrl.class); 23 private static final String HTTP_URL = "https://origin.cpc.ncep.noaa.gov/products/people/mchen/CFSv2FCST/monthly/"; 24 private static final String IMAGE_PATH = "E:\Projects\image"; 25 26 public static void main(String[] args) { 27 try { 28 Document document = Jsoup.connect(HTTP_URL).get(); 29 Element table = document.getElementsByTag("table").get(0); 30 Elements trs = table.select("tr"); 31 for (int i = 2; i < trs.size(); i++) { 32 Element td = trs.get(i).select("td").get(1); 33 Elements a = td.select("a[href^=images]"); 34 String image = a.attr("href"); 35 String imgUrl = HTTP_URL + image; 36 downImages(imgUrl); 37 } 38 logger.info("本组图片已全部保存到" + IMAGE_PATH); 39 } catch (IOException e) { 40 e.printStackTrace(); 41 logger.error("读取页面内容失败"); 42 } 43 } 44 45 /** 46 * @param [imgUrl] 47 * @return void 48 * @author 清风明月 49 * @date 2019/7/16 13:59 50 */ 51 private static void downImages(String imgUrl) { 52 File imgFilePath = new File(IMAGE_PATH); 53 //如果目录不存在,创建目录 54 if (!imgFilePath.exists()) { 55 boolean mkdir = imgFilePath.mkdir(); 56 logger.info(mkdir ? "程序已自动创建目录" : ""); 57 } 58 //拼接image下载地址 59 String beforeUrl = imgUrl.substring(0, imgUrl.lastIndexOf("/") + 1); 60 String imgName = imgUrl.substring(imgUrl.lastIndexOf("/") + 1); 61 String newImgName = imgName; 62 63 try { 64 newImgName = URLEncoder.encode(imgName, "UTF-8"); 65 } catch (UnsupportedEncodingException e) { 66 logger.error("图片名称有误"); 67 e.printStackTrace(); 68 } 69 imgUrl = beforeUrl + newImgName; 70 try { 71 //获取下载地址 72 URL url = new URL(imgUrl); 73 InputStream in = null; 74 OutputStream out = null; 75 try { 76 //链接网络地址,创建连接对象 77 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 78 //建立到远程对象的实际连接 79 connection.connect(); 80 //连接成功 81 if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) { 82 //获取链接的输入流 83 in = connection.getInputStream(); 84 //创建下载到本地的文件 85 File imgFile = new File(IMAGE_PATH, imgName); 86 if (imgFile.exists()) { 87 logger.info(imgName + " 该图片已存在"); 88 } else { 89 //写入文件 90 out = new FileOutputStream(imgFile); 91 byte[] buf = new byte[1024]; 92 int len; 93 while ((len = in.read(buf)) != -1) { 94 out.write(buf, 0, len); 95 } 96 out.flush(); 97 //断开连接 98 connection.disconnect(); 99 logger.info(imgName + "下载成功"); 100 } 101 } else { 102 logger.warn("连接失败"); 103 } 104 105 } catch (IOException e) { 106 logger.error("下载图片失败"); 107 e.printStackTrace(); 108 } finally { 109 try { 110 if (out != null) { 111 out.close(); 112 } 113 114 if (in != null) { 115 in.close(); 116 } 117 } catch (IOException e) { 118 logger.error("读写流关闭出现异常"); 119 e.printStackTrace(); 120 } 121 } 122 } catch (MalformedURLException e) { 123 logger.error("网址格式错误"); 124 e.printStackTrace(); 125 } 126 } 127 }
至此,大功告成。
最后给各位提两点建议(包括我):
- 调用close()方法前,手动加上flush()方法,并且close()方法尽量放在finally中,不要偷懒。否则有可能出现文件(包括图片、word文档等)下载完成却无法打开的情况;
- 如果下载的文件只有1KB,建议查看URL是否正确(例如https://少了s);
“我将永远忠于自己,披星戴月奔向理想和你”