给个需求:通过HTTP协议来获取指定网页的图片,并下载到本地,且用照片的名字来命名照片。这里我就拿学校的官网来作为指定网页,来实现下载官网图片的功能。
至于如何用HTTP协议制作一个简易的客户端,可以参考我之前写的一篇文章:
手写一个简易的安卓客户端:https://segmentfault.com/a/1190000043478702
如何获取官网上的图片信息。首先我们要知道,我们该如何获取网页上的图片信息。我们通过请求服务器展示图片的网页的相关路径,服务器就会返回一个HTML页面的响应。而这个HTML页面里就有许许多多的<img>标签,图片的相关信息就存放在这个标签之中。以我学校的官网举例:
所以我们要做的事情就是利用正则表达式来提取HTML页面中<img>标签。
1、创建一个简易的http客户端类,连接到指定的服务端
public class Client {
private int port = 80 ;//这个是http协议的默认端口号
private String host = "指定网页的远程地址";
String url;
public Client(){
}
public Client(int port,String host){
this.port = port;
this.host = host;
}
public void clientServer() throws IOException{
System.out.println("连接上服务器");
Socket socket = new Socket(host, port);
}
public void writeToServerGET(OutputStream clientOut,String url ,String host,int port) throws IOException {
clientOut.write(("GET" +" "+url+" "+"HTTP/1.1"+"\r\n").getBytes());
clientOut.write(("Accept:"+" "+"text/html"+"\r\n").getBytes());
clientOut.write(("HOST:"+" "+ host+":"+port+"\r\n").getBytes());
clientOut.write(("Connection: "+"keep-alive"+"\r\n").getBytes());
clientOut.write("\r\n".getBytes());
clientOut.flush();
}
public static void main(String[] args) throws IOException {
new Client().clientServer();
}
}
2、在Client类中创建读取输入流的方法readResponse()方法
public String readResponse(BufferedReader bufferedReader) throws IOException {
String RSHttp="";
String str = "";
//将读取到的请求报文按行读取
while ((str=bufferedReader.readLine())!= null){
RSHttp +="\r\n" +str;
System.out.println(str);
}
return RSHttp;
}
**3、给出getMatchStringSrc()方法以及getMatchStringAlt()方法。
我们要做的就是提取<img>标签中的src、alt**
public static List<String> getMatchStringAlt(String string){
List<String> alts = new ArrayList<>();
Pattern compile = null ;
compile = Pattern.compile("<img.*?>");
Matcher matcher = compile.matcher(getMatchStringClass(string).toString());//这里调用了getMatchStringClass()方法
while (matcher.find()){
String img = matcher.group();
Matcher m = Pattern.compile("alt\\s*=\\s*\"?\\s*(.*?)(\"|>|\\s+)").matcher(img);
if(m.find()){
String group = null;
group = m.group();
System.out.println(group);
alts.add(group.substring(5,group.length()-1));
}
}
return alts;
}
public static List<String> getMatchStringSrc( String string){
List<String> pics = new ArrayList<>();
//实例化 compile
Pattern compile = null;
compile = Pattern.compile("<img.*?>");//利用正则表达式来获取到html中指定的标签<img>
//比较是否寻找到
Matcher matcher = compile.matcher(getMatchStringClass(string).toString());
/*
*尝试查找与模式匹配的输入序列的下一个子序列。
当且仅当输入序列的子序列匹配此匹配器的模式时返回:true
* */
while (matcher.find()) {
String img = matcher.group();
//Matcher得利用Pattern来实例化
Matcher m = Pattern.compile("\"http?(.*?)(\"|>|\\s+)").matcher(img);//利用正则表达式来获取<img>标签中的url
m.find();
//group()前一个匹配以字符串形式匹配的子序列(可能为空,就是没有 find()方法没有找到下一个匹配的子序列时为空)
String group = m.group();
System.out.println(group);
pics.add(group.substring(1, group.length() - 1));
}
return pics;
}
可以看到,我在getMatchStringSrc()方法以及getMatchStringAlt()方法中还调用了一个getMatchStringClass()方法,这是应为在一个网页中有许许多多的图片信息,以我学校的官网举例:
而我们要获取的只是那些照片信息,所以不能提取所有的<img>,我们要把符合需求的<img>提取出来,所以要利用getMatchStringClass()方法,缩小提取的范围
public static List<String> getMatchStringClass(String string){
List<String> names = new ArrayList<>();
Pattern compile = null;
compile =Pattern.compile("<div\\s.*?><img.*?>");
Matcher matcher =compile.matcher(string);
while(matcher.find()){
String div = matcher.group();
Matcher m =Pattern.compile("class\\s*=\\s*\"?(.*?)(\"|>|\\s+)").matcher(div);
m.find();
String group = null;
group = m.group();
if(group.equals("class=\"page_news_lists\"")){//获取class=page_news_lists 的div作为接下来提取<img>标签的范围
names.add(div);
}
}
return names;
}
4、进行逻辑处理
public void clientServer() throws IOException{
System.out.println("连接上服务器");
Socket socket = new Socket(host, port);
//目标路径
url = "/html/cmfy/xiaoyou/";
OutputStream clientOut = socket.getOutputStream();
//发送封装好的请求报文
writeToServerGET(clientOut,url,host,port);
System.out.println("url发送成功");
//获取字节流
InputStream clientIn = socket.getInputStream();
//转为字符流
BufferedReader buf = new BufferedReader(new InputStreamReader(clientIn,"UTF-8"));
System.out.println("拆解响应内容");
//读取响应的html
String result = readResponse(buf);//调用了readResponse()方法
//将getMatchString()方法返回的图片路径存放在 picture集合中
List<String> picture = new ArrayList<>();
picture = getMatchStringSrc(result);//调用了getMatchStringSrc()方法,获取对应图片在网页上的下载路径
int count = picture.size();//集合的元素个数
System.out.println(count);
List<String> alt = new ArrayList<>();
alt = getMatchStringAlt(result);//调用了getMatchStringAlt()方法,获取对应图片的姓名
int count2 = alt.size();
System.out.println(alt);
//将SRC转化为字符串按','分割。 这个方法行不通,将集合转为字符串之后,有一对'[]'处理不了
/*String SRC = picture.toString();
System.out.println(SRC); */
while(count>0){
//get()返回列表中指定位置的元素。
String name = alt.get(count2-1);
String path = picture.get(count-1);
System.out.println("还剩"+count+"张");
System.out.println(name);
System.out.println(path);
//读取到图片路径后下载
URL url = new URL(path);
DataInputStream dataInputStream = new DataInputStream(url.openStream());
String newImageName="E://picture/"+name +".jpg";//将图片存放的路径赋值给newImageName
byte[] buffer = new byte[1024];
int length = 0;
//打开指定路径的文件夹 newImageName
FileOutputStream fileOutputStream = new FileOutputStream(new File(newImageName));
//将图片读入fileOutputStream
while((length = dataInputStream.read(buffer))>0){
fileOutputStream.write(buffer,0,length);
}
System.out.println("上传成功");
dataInputStream.close();
fileOutputStream.close();
count--;
count2--;
}
clientOut.close();
System.out.println("打印完成");
}
执行!
可以看到,图片已经下载到本地,且以名字作为图片的命名方式。
总结:
1、我通过浏览器请求学校官网,获得了学校官网的远程地址和端口号
2、创建get_Picture项目,首先定义一个port和host,创建构造方法Client(),通过构造方法将port和host传入clentServer()方法中的Socket socket = new Socket(host, port);
3、与服务器进行连接之后,向服务器发送一个Get请求,请求的路径为"/html/cmfy/xiaoyou/",等待服务器响应
4、将服务器响应的内容通过InputStream读取,再通过BufferedReader将读取到的字节流转化为字符流
5、创建一个读取字符流的方法readResponse()进行按行读取。
6、在clientServer()方法中调用readResponse()方法(将获取到的字符流按行打印),并返回给clientServer()
7、创建一个拆解出html中图片地址的方法getMatchString(),返回一个集合。
8、clientServer()方法获取到readResponse()方法返回String值之后,调用getMatchStringSrc()方法和getMatchStringAlt()方法,将String值作为参数传入到这两给方法之中
9、getMatchStringSrc()方法和getMatchStringAlt()方法中调用getMatchStringClass()方法,来获取指定地区的图片信息
8、在clientServer()方法中创建一个集合用来储存getMatchStringSrc()方法和getMatchStringAlt()方法返回的集合
9、获取将创建的集合的长度作为while循环的条件(长度大于0),将集合中的元素提取出来
10、在clientServer()方法中指定一个路径作为存储图片的地方,使用FileOutputStream类new出来的对象fileOutputStream来打开这个文件,
11、通过fileOutputStream.write方法将图片信息写入到对应的地址当中,完成图片的下载
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。