Java中模拟浏览器访问网页(三)

Java中模拟浏览器访问网页(三)

转载:https://blog.csdn.net/qq122627018/article/details/51473150

一.前言

看完上一节中浏览器访问网页的行为分析之后,你是不是很好奇在Java程序中要怎么去访问一个网页呢?先来回想一下浏览器访问网页的最基本流程:
封装请求->发送请求->接收响应->解析并作出动作
那么在Java中,我们要完成这套动作,用到的就是HttpURLConnection这个类,他可以帮助我们去完成一个请求网页的动作

二.如何发送一个请求

HttpUrlConnection实例

HttpUrlConnection是Java自带的类,所以并不需要导入第三方的jar包,而在通常情况下,获取HttpUrlConnection实例的方法是通过一个URL来打开一个连接从而获取实例,如下:

HttpURLConnection conn = null;
try {

    URL realUrl = new URL("www.163.com");
    conn = (HttpURLConnection) realUrl.openConnection();
}catch (Exception e) {
    //Url出错
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这里值得注意的是,这样仅仅是打开一个连接而已,此时并未发送请求,接下来要做的,是设置HttpUrlConnection的参数:

            //设置post方法
            conn.setRequestMethod("POST");
            //不使用缓存
            conn.setUseCaches(false);
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            //读取超时时间
            conn.setReadTimeout(8000);
            //连接超时时间
            conn.setConnectTimeout(8000);
            //这一句很重要,设置不要302自动跳转,后面会讲解到
            conn.setInstanceFollowRedirects(false);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

到这里,一个HttpUrlConnection的实例就准备好了,接下来继续设置这个请求的其他数据

设置请求头

设置请求头也就是请求头部,在第二节中也讲解过请求头部的作用,目的是告诉服务器一些关于客户端的信息,有时候这些请求头部也会被当作服务器验证客户端的一些参数,如Referer头部,这个头部会告诉服务器我在请求你这个网页之前是从哪里跳转过来的。话不多说,下面上代码:

conn.setRequestProperty(key, value);
  • 1

其实也就一句代码哈哈,但是一般情况下,都是自己封装好参数和值在一个map集合中,然后通过循环设置在conn中,如下:

 for (Map.Entry<String, String> entry : sendData.getHeaders()
                        .entrySet()) {
                    conn.setRequestProperty(entry.getKey(), entry.getValue());
                    //Log.i("wang","header中包含:"+entry.getKey()+":"+entry.getValue());
                }
  • 1
  • 2
  • 3
  • 4
  • 5

设置参数

设置参数只有在post请求的时候才需要用到这个方法,因为get请求是直接把参数封装到url中;下面看看代码:

    //模拟参数
    String pars = "name=w&class=12";
    out = new PrintWriter(conn.getOutputStream());
    // 发送请求参数
    out.print(pars);
    // flush输出流的缓冲
    out.flush();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

到这里,我们已经准备好一个请求了,那怎么发送给服务器呢?其实,在HttpUrlConnection中,并没有发送请求这个方法,而是通过获取返回码的函数,来让HttpUrlConnection把这个请求发送出去:

    int responseCode = conn.getResponseCode();
  • 1

接下来看看怎么处理服务器的回应

三.接收响应

判断响应码

从上面我们已经知道了怎么获取响应码,在接收服务器返回给我们的数据之后,第一步就要判断响应码,在第二节中也说过,响应码是服务器处理请求状态的标识
在一般抓包的过程当中,200代表这服务器处理请求成功;302代表着重定向,也就是跳转到另外一个地址;
但是,这里要特别指出,不是说得到响应码200就一定代表着你请求数据成功。举个例子:在登录的过程中,由于密码错误网页弹出提示框,此时得到的也是响应码200,所以在这里不能说你请求数据成功,很多时候还是要看情况而定。

扫描二维码关注公众号,回复: 457291 查看本文章

处理响应头

有人可能会问道,其实响应头在实际应用中并没有什么用呀,为什么要去关注它;
其实响应头在抓包过程中也扮演着重要的角色,具体体现在Location和Set-Cookie这俩个头部
Location
location头部就是当收到返回码302的时候指定的转发地址,所以在判断返回码是302的时候,必须取出相应头中的location值,然后再次封装请求进行访问
Set-Cookie

set-cookie头是服务器要求客户端保存在本地的cookie值,所以这个头部关系到在web访问中一些”状态的保持”,比如登录状态。关于这个头部有必要举个例子:
eg:当用户访问登录页面的时候,服务器会返回一串cookie值,此时用户必须保存在本地,当点击登录按钮的时候,客户端会把此cookie还有用户名密码发送给服务器,当验证通过时,每次访问服务器的每个子页面的时候客户端都会带上此cookie,以让服务器验证本用户是否已经登录
那上面的逻辑在Java程序中的处理方法就是:发送一个登录页面的请求,收到响应后取出响应头中的set-cookie值保存在本地,当要进行模拟登录的时候,把此值封装到请求头中的cookie一并发送,完成登录。

处理响应正文

处理了响应头之后,就到了我们的主角–响应正文了。获取响应正文的方式:

    BufferedReader in = null;
    String result = "";
    // 定义BufferedReader输入流来读取URL的响应
    in = new BufferedReader(new InputStreamReader(
            conn.getInputStream(), "utf-8"));
    String line;
    while ((line = in.readLine()) != null) {
        Log.i("wang","line="+line);
        result += line;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

此处获取的result就是我们的响应正文,也就是html代码.我们要的数据就在里面。

四.实践

临时写的一个模拟访问网页的demo:

 HttpURLConnection conn = null;
                try {
                    URL realUrl = new URL(url);
                    conn = (HttpURLConnection) realUrl.openConnection();
                    conn.setRequestMethod("GET");
                    conn.setUseCaches(false);
                    conn.setReadTimeout(8000);
                    conn.setConnectTimeout(8000);
                    conn.setInstanceFollowRedirects(false);
                    conn.setRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0");
                    int code = conn.getResponseCode();
                    if (code == 200) {
                        InputStream is = conn.getInputStream();
                        BufferedReader in = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                        StringBuffer buffer = new StringBuffer();
                        String line = "";
                        while ((line = in.readLine()) != null){
                            buffer.append(line);
                        }
                        String result = buffer.toString();
                        //subscriber是观察者,在本代码中可以理解成发送数据给activity
                        subscriber.onNext(result);
                    }
                }catch (Exception e){
                    subscriber.onError(e);
                }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

附上demo截图:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/budaoweng0609/article/details/80089159