给个需求:通过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方法将图片信息写入到对应的地址当中,完成图片的下载


爱摇头的电风扇
7 声望2 粉丝