网络爬虫-http请求方式

来源:互联网 发布:淘客采集上传淘宝店铺 编辑:程序博客网 时间:2024/05/16 18:40

首先对http做简单的介绍:

超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。
HTTP是一个客户端和服务器端请求和应答的标准(TCP)。客户端是终端用户,服务器端是网站。通过使用Web浏览器、网络爬虫或者其它的工具,客户端发起一个到服务器上指定端口(默认端口为80)的HTTP请求。

HTTP通信机制是在一次完整的HTTP通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤:

(1) 建立TCP连接
在HTTP工作开始之前,Web浏览器首先要通过网络与Web服务器建立连接,该连接是通过TCP来完成的,该协议与IP协议共同构建Internet,即著名的TCP/IP协议族,因此Internet又被称作是TCP/IP网络。HTTP是比TCP更高层次的应用层协议,根据规则,只有低层协议建立之后才能,才能进行更层协议的连接,因此,首先要建立TCP连接,一般TCP连接的端口号是80。
(2) Web浏览器向Web服务器发送请求命令
一旦建立了TCP连接,Web浏览器就会向Web服务器发送请求命令。
(3) Web浏览器发送请求头信息
浏览器发送其请求命令之后,还要以头信息的形式向Web服务器发送一些别的信息,之后浏览器发送了一空白行来通知服务器,它已经结束了该头信息的发送。
(4) Web服务器应答
客户机向服务器发出请求后,服务器会客户机回送应答。
(5) Web服务器发送应答头信息
正如客户端会随同请求发送关于自身的信息一样,服务器也会随同应答向用户发送关于它自己的数据及被请求的文档。
(6) Web服务器向浏览器发送数据
Web服务器向浏览器发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束,接着,它就以Content-Type应答头信息所描述的格式发送用户所请求的实际数据
(7) Web服务器关闭TCP连接
一般情况下,一旦Web服务器向浏览器发送了请求数据,它就要关闭TCP连接,然后如果浏览器或者服务器在其头信息加入了这行代码
Connection:keep-alive
TCP连接在发送后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽。

http 请求:

组成部分:请求行、请求头、请求体

请求行:请求信息的第一行
  • 格式:请求方式 访问的资源 协议/版本
  • 例如:GET /myWeb/1.html HTTP/1.1
  • 请求方式:get和post
  • get会把参数放在url的后面 post不会
  • get参数大小有限制,post请求却没有限制
  • get请求没有请求体;post请求有请求体 请求参数放在请求体中
请求头:请求信息的第二行到空行结束
  • 格式:key/value (value可以是多个值)
  • 常见的请求头:
  • Accept: text/html,image/bmp –支持数据类型 text/html text/css text/javascript 大类型/小类型 mime类型
  • Accept-Charset: ISO-8859-1 –字符集
  • Accept-Encoding: gzip –支持压缩
  • Accept-Language:zh-cn –语言环境
  • Host: www.zack.cn:80 –访问主机
  • If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT –缓存文件的最后修改时间
  • Referer: http://www.test.com/index.jsp –来自哪个页面、防盗链
  • User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)
  • Cookie
  • Connection:Keep-Alive –链接状态
  • 掌握的头信息:
  • Referer User-Agent Cookie If-Modified-Since
请求体:空行以下的内容
  • 只有post才有请求体 get请求参数 http://xxxx?username=tom&password=123
  • 格式:username=tom&password=123

http 响应:

组成部分:响应行 响应头 响应体

响应行:响应信息的第一行

  • 格式:协议/版本 状态码 状态码说明
  • 例如:HTTP/1.1 200 OK
  • 状态码:
  • 200 正常响应成功
  • 302 重定向
  • 304 读缓存
  • 404 用户操作资源不存在
  • 500 服务器内部异常

响应头:从响应信息的第二行到空行结束

  • 格式:key/value(value可以是多个值)
  • 常见的头
  • Location: http://www.it315.org/index.jsp –跳转方向 和302一起使用的
  • Server:apache tomcat –服务器型号
  • Content-Encoding: gzip –数据压缩
  • Content-Length: 80 –数据长度
  • Content-Language: zh-cn –语言环境
  • Content-Type: text/html; charset=GB2312 –数据类型
  • Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT –最后修改时间
  • Refresh: 1;url=http://www.it315.org –定时刷新
  • Content-Disposition: attachment; filename=aaa.zip –下载
  • Set-Cookie:SS=Q0=5Lb_nQ; path=/search
  • Expires: -1 –缓存
  • Cache-Control: no-cache –缓存
  • Pragma: no-cache –缓存
  • Connection: Keep-Alive –连接
  • 掌握的头信息
  • Content-Type Location Last-Modified Refresh Content-Disposition Set-Cookie

响应体:空行以下的内容

    页面上展示的内容

响应正文响应正文就是服务器返回的HTML页面:

<html><head><title>HTTP响应示例<title></head><body>Hello HTTP!</body></html>

响应头和正文之间也必须用空行分隔。

get和post请求的区别分析:

    1,    get提交,提交的信息都显示在地址栏中。    post提交,提交的信息不显示地址栏中。    2,    get提交,对于敏感的数据信息不安全。    post提交,对于敏感信息安全。    3,    get提交,对于大数据不行,因为地址栏存储体积有限。    post提交,可以提交大体积数据。     4,    get提交,将信息封装到了请求消息的请求行中。    post提交,将信息封装到了请求体中。    在服务端的一个区别。    如果出现将中文提交到tomcat服务器,服务器默认会用iso8859-1进行解码会出现乱码,    通过iso8859-1进行编码,在用指定的中文码表解码。即可。    这种方式对get提交和post提交都有效。     但是对于post提交方式提交的中文,还有另一种解决办法,就是直接使用服务端一个对象    request对象的setCharacterEncoding方法直接设置指定的中文码表就可以将中文数据解析出来。    这个方法只对请求体中的数据进行解码。 

模拟浏览器发送get请求:

public class SendGet {    public String sendGet(String url, String param, String charset, String cookie, boolean isNew) {        int HttpResult; // 服务器返回的状态        int tryI = 0;        String result = "";        HttpURLConnection httpConn = null;        BufferedReader in = null;        StringBuffer pageContent = null;        URL U = null;        while (result.equals("") && tryI < 3) {            try {                pageContent = new StringBuffer(4096);// StringBuffer的缓冲区大小                String urlName = "";                int timeOut = (tryI * 10 + 1) * 60000;// 超时设置                if (!param.trim().equals("")) {                    urlName = url + "&" + param;//                } else {                    urlName = url;                }                U = new URL(urlName);                HttpURLConnection httpconn = (HttpURLConnection) httpConn;// 获取HttpUrlConnection实例                httpconn = (HttpURLConnection) U.openConnection(); // 打开一个链接                httpconn.setRequestProperty("User-Agent", // httpconn.setRequestProperty设置请求头参数                        "Mozilla/4.0 (compatible; MSIE 6.01; Windows NT 5.0)");                httpconn.setRequestProperty("Content-type", "application/octet-stream");                httpconn.setRequestProperty("Connection", "Keep-Alive");                httpconn.setUseCaches(false);                httpconn.setConnectTimeout(timeOut);                httpconn.setReadTimeout(timeOut);                if (cookie != null && !cookie.equals("")) {                    httpconn.setRequestProperty("Cookie", cookie);                }                httpconn.connect();                // HttpResult = httpconn.getResponseCode();                // if (HttpResult != HttpURLConnection.HTTP_OK) {//                // 不等于HTTP_OK说明连接不成功                // if (tryI == 2) {                // System.out.println("无法连接到" + url + "?" + param);                // System.err.println("HttpResult=" + HttpResult                // + " SendGet无法连接到" + url + "?" + param);                // }                // } else {                // 定义BufferedReader输入流来读取URL的响应in=new BufferedReader(new                // InputStreamReader                in = new BufferedReader(new InputStreamReader(httpconn.getInputStream(), charset));                int i = 0;                String line = in.readLine();// readLine()读取文件,以行为单位,一次读一行,一直读到null时结束,每读一行都显示行号。                boolean flag = true;                while (line != null) {                    pageContent.append(line);// append():像动态字符串数组 Stringbuffer添加                    line = in.readLine();                    if (i > 15000 && flag) {                        System.err.println("sendGet 抓取:" + url + "\t返回的页面行数太多,可能出错,行数大于" + i);                        flag = false;                    }                    i++;                }                in.close();                in = null;                result = pageContent.toString() + "";                pageContent.delete(0, pageContent.length());                pageContent = null;                // }                httpconn.disconnect();// 断开请求                if (httpConn != null) {                    httpConn = null;                }            } catch (Exception e) {                if (tryI == 2) {                    e.printStackTrace();                    System.err.println("sendGet第" + tryI + "次 抓取出错!" + url + "?" + param);                }                try {                    Thread.sleep(tryI * 1000);                } catch (InterruptedException e1) {                    e1.printStackTrace();                }                pageContent = null;            } finally {                if (in != null) {                    try {                        in.close();                    } catch (IOException e) {                        // TODO 自动生成 catch 块                        e.printStackTrace();                    }                    in = null;                }                if (httpConn != null) {                    httpConn = null;                }                pageContent = null;                U = null;            }            tryI++;        }        if (pageContent != null) {            pageContent.delete(0, pageContent.length());            pageContent = null;        }        return new String(result.replaceAll("\r\n", "<br>"));// replaceAll(str1,str2)把str1用str2换掉    }    /**     * Get方法(不用输入Cookie的)     *      * @param url     * @param param     * @param charset     * @return     */    public static String sendGet(String url, String param, String charset) {        SendGet get = new SendGet();        String tmp = "";        tmp = get.sendGet(url, param, charset, "", true);        get = null;        url = null;        param = null;        charset = null;        return tmp;    }    public static String sendGet(String url, String param, String charset, String cookie) {        SendGet get = new SendGet();        String tmp = get.sendGet(url, param, charset, cookie, true);        get = null;        url = null;        param = null;        charset = null;        cookie = null;        return tmp;    }}

模拟浏览器发送post请求:

public class SendPost {    /* StringBuffer的缓冲区大小 */    //protected final static int TRANSFER_SIZE = 4096;    /**     * Post方法     *      * @param url     * @param param     * @param charset     * @param cookie     * @return     */    public  String sendPost(String url, String param, String charset, String cookie, boolean isNew) {        int HttpResult; // 服务器返回的状态        int tryI = 0;        String result = "";        HttpURLConnection httpConn = null;        BufferedReader in = null;        StringBuffer pageContent =  null;        PrintWriter out = null;        URL httpurl = null;        while (result.equals("") && tryI < 3) {            try {                pageContent =  new StringBuffer(4096);                int timeOut = (tryI * 10 + 1) * 60000;                httpurl = new URL(url);                HttpURLConnection httpconn = (HttpURLConnection) httpConn;                httpConn = (HttpURLConnection) httpurl.openConnection();                httpConn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.01; Windows NT 5.0)");                httpConn.setRequestProperty("Content-type", "application/x-www-form-urlencoded");//              httpConn.setRequestProperty("Content-type", "multipart/form-data");                httpConn.setConnectTimeout(timeOut);                httpConn.setReadTimeout(timeOut);                httpConn.setUseCaches(false);                httpConn.setDoOutput(true);                httpConn.setDoInput(true);                httpConn.setAllowUserInteraction(false);                if (cookie != null && !cookie.equals("")) {                    httpConn.setRequestProperty("Cookie", cookie);                }                httpConn.connect();//              HttpResult = httpconn.getResponseCode();//              if (HttpResult != HttpURLConnection.HTTP_OK) {// 不等于HTTP_OK说明连接不成功//                  if (tryI == 2) {//                      System.out.println("HttpResult="+HttpResult+" 无法连接到" + url + "?" + param);//                      System.err.println("HttpResult="+HttpResult+" SendPost无法连接到" + url + "?" + param);//                  }//              } else {                    out = new PrintWriter(httpConn.getOutputStream());                    out.print(param);                    out.flush();                    out.close();                    in = new BufferedReader(new InputStreamReader(httpConn.getInputStream(), charset));//                  String line = "";//                  while ((line = in.readLine()) != null) {//                      pageContent.append(line);//                  }                    int i=0;//                  while (in.read() != -1) {//                      pageContent.append(in.readLine());//                      if(i>10000) {//                          System.err.println("sendPost 抓取出错,循环次数过多:"+i);//                      }//                      i++;//                  }                    String line = in.readLine();                    boolean flag = true;                    while (line != null) {                        pageContent.append(line);                        line = in.readLine();                        if(i>15000 && flag) {                            System.err.println("sendPost 抓取:"+url+"\t返回的页面行数太多,可能出错,行数大于"+i);                            flag = false;                        }                        i++;                    }//                  while ((line = in.readLine()) != null) {//                      pageContent.append(line);//                      if(i>10000) {//                          System.err.println("sendPost 抓取出错,循环次数过多:"+i);//                      }//                      i++;//                      line = null;//                  }                    in.close();                    in = null;                    //result = pageContent.toString();                  //              }                result = new String(pageContent.toString()+"");                pageContent.delete(0, pageContent.length());                pageContent = null;                out = null;                httpConn.disconnect();            } catch (Exception e) {                if (tryI == 2) {                    e.printStackTrace();                    System.err.println("sendPost 第" + tryI + "次 抓取出错!" + url + "?" + param);//                  if (SysConstant.logger.isDebugEnabled()) {//                      SysConstant.logger.debug("sendPost 第" + tryI + "次 抓取出错!" + url + "?" + param);//                  }                }                try {                    Thread.sleep(tryI * 1000);                } catch (InterruptedException e1) {                    e1.printStackTrace();                }                pageContent = null;            } finally {                if (in != null) {                    try {                        in.close();                    } catch (IOException e) {                        // TODO 自动生成 catch 块                        e.printStackTrace();                    }                    in = null;                }                pageContent = null;                out = null;                httpurl = null;                         }            tryI++;        }        if (pageContent != null) {            pageContent.delete(0, pageContent.length());            pageContent = null;        }        return new String(result.replaceAll("\r\n", "<br>"));    }    /**     * Post方法(不用输入Cookie的)     *      * @param url     * @param param     * @param charset     * @return     */    public static String sendPost(String url, String param, String charset) {        SendPost get = new SendPost();        String tmp =  get.sendPost(url, param, charset, "", true);        get = null;         url = null;        param = null;        charset = null;        return tmp;    }    /**     * Post方法(不用输入Cookie的)     *      * @param url     * @param param     * @param charset     * @return     */    public static String sendPost(String url, String param, String charset, String cookie) {        SendPost get = new SendPost();        String tmp =  get.sendPost(url, param, charset, cookie,true);        get = null;         url = null;        param = null;        charset = null;        cookie = null;        return tmp;    }}