Python 爬虫教程 2 - HTTP协议

时间:2022-01-01 06:16:18

什么是 HTTP

HTTP是一种应用层协议,是一种在网络中进行数据传输时,收发双方提前达成的某些共同约定,HTTP 协议涵盖的内容极广,而这里我们主要关注 HTTP 在报文格式上的约定。首先会对如何对 HTTP 中资源进行定位,然后介绍下 HTTP 报文结构,接下来介绍下 HTTP 的请求和响应,最后给出一个示例。

通过 URL 对资源进行定位

URL 的全称是(统一资源定位符),通过对网络中资源位置的描述来对其进行唯一的标识,这并不属于 HTTP 协议的内容,但却十分重要。我们在互联网上无时无刻不在使用着 URL,例如在用浏览器访问网站时在地址栏所输入的就是一个 URL,它唯一的标识了一个网站。
用我在 **** 的博客地址来举例 http://blog.****.net/preyta,这就是一个 URL,它由三部分组成:
- 第一部分 http://,这一部分是 URL 方案,它用来标识可以用什么样的协议访问资源,除了 http 以外还有许多常用的方案,例如:文件服务器采用的 ftp 和远程登录服务器用的 sftp 等。
- 第二部分 blog.****.net,这是指服务器的位置,也就是我们常说的一个网站的域名。
- 第三部分/preyta,这是指资源在服务器上的路径,这个路径不是实际的文件路径,只是一个对资源的标识。
上面三个部分组合在一起唯一的标识了一个资源可以通过什么协议访问,在哪一个服务器上,是哪一个资源。

除了上面的三个基本的组成部分,一个 URL 还有一些可选组件,其中比较重要的是查询字符串,你可以打开百度随便搜索一个词,然后查看地址栏的 URL,可以看到除了上面所说的三部分,在最后多了一个问号,会是类似这样的一个 URL https://www.baidu.com/s?wd=hello%20world(这里我搜索的是 hello world ,并省略掉了无关部分)。问号后面的内容就被称为查询字符串,它们是以键值对的形式出现的,紧跟在问号后面。我这里就是表明需要传递的数据为wd=hello%20world,即搜索关键字是 hello%20world 。可能有人会问明明你的搜索关键字是 hello world,但是传递到 URL 的时候多了 %20 这样一个奇怪的东西。其实这是 URL 的转义机制在起作用, 将空格转换成了 %20,具体的转义内容这里就不再展开,感兴趣的同学可以自行百度一下。

HTTP 数据交互流程

以网页浏览为例,当我们在浏览器打开一个网页的时候就是从客户端发送了一次 HTTP 请求,服务器接收到该请求,返回一个对应的 HTTP 响应,浏览器对响应内容进行解析并显示在屏幕上。这就是一个 HTTP 的全过程。


Python 爬虫教程 2 - HTTP协议

HTTP 报文

在使用 HTTP 协议进行交流时,实际上发送和接收的都是 HTTP 报文,而由上面的数据交互流程可以看出,实际上有两次数据交互,一次请求一次响应,所以相对应的也有两种不同的报文,分别为请求报文和响应报文。

请求报文

如下图所示,请求报文由三部分组成:


Python 爬虫教程 2 - HTTP协议

  1. 起始行
    它表明了本次请求要对什么资源采取什么操作,包括请求的动作,请求的 URL 以及使用的 HTTP 版本。
    • 请求的动作是 HTTP 的动词,有 GET,POST,PUT,DELETE,HEAD,OPTION,它们有各自不同的语义,但是在网页中所常用的就是 GET 和 POST 两种。GET 表示对一个资源进行获取,通常的请求都是 GET 方法;而 POST 表示对资源提交一些数据,在网页中填写如账号密码等表单或者上传图片等会用到 POST 方法。关于其他 HTTP 方法的作用由于篇幅有限,感兴趣的同学可以去百度一下,在我的关于 Restful Web Service 的几篇博客中也有涉及。
    • 请求的 URL 就是上一节提到的,但是只包括了资源在服务器上的路径这个部分。
    • 最后一个是 HTTP 版本,由于 HTTP 在发展中有一些变化,各版本之间存在着差异,为了保证客户端和服务器的协议内容能够匹配而添加了版本号。
  2. 报文头
    如果说起始行表明了本次请求的最基本描述,那么报文头则通过键值对的方式,提供了对传输的额外描述。
    以图中的请求为例,有两个首部,分别是 Accept 和 Host,Accept 告诉服务器本客户端只接收类型为 html 的文本数据,服务器就会根据请求和实际的资源返回对应的响应;而 Host 用于指明本次请求的服务器信息。HTTP 定义的数量众多的报文头用于控制传输的方方面面,详细的资料请自行翻阅相关书籍。
  3. 报文体
    前面两部分都是对请求的描述,这一部分终于是实实在在的通过 HTTP 协议承载的实际数据了。但是在常用的 GET 方法中,这个部分通常是空的,因为 GET 方法不需要提交数据,仅仅是获取数据;而 POST 方法上传一些文件时,文件就会以二进制字符串的形式包含在报文体里。

响应报文

和请求报文类似,响应报文也由三部分组成:


Python 爬虫教程 2 - HTTP协议

1. 起始行
这个起始行由两部分组成,第一个是 HTTP 版本,和上面类似;另一个是一个数字,叫做状态码,表明了响应的状态是成功,失败还是其他情况。这里的200是最常见的状态码表示成功。
2. 报文头
和请求报文头类似,只是请求和响应的报文头的首部有一些区别,有一些报文头是请求独有的,有一些是响应独有的,还有一些事通用的报文头。上图的 Content-Type 表示返回的报文体类型是 html 文档。而 Content-Length 指明了返回的报文体的长度。
3. 报文体
这一部分和前面请求报文里的报文体内容类似,只是是由服务器返回给客户端的数据。我们通过浏览器获取的网页文档就是以 html 格式的数据放在这里的。

常用的状态码

  • 200 OK,正常网页请求的状态码,表明该请求成果返回。2 开头的都被称为成功状态码,只是不同的成功状态,例如 201 Created,这个在异步的请求十分重要。
  • 301 Moved Permanently,表示资源被暂时转移到了其他地方,会在响应的 Location 首部给出转义到的 URL。3 开头的被称为重定向状态码,指明了各种不同的重定向理由,比如 300 Multiple Choice,302 Found。
  • 404 Not Found,表示找不到对应资源。4 开头的状态码都表明客户端出现了错误,或者是请求了错误的 URL(404) 或者是还未登录(401 Unauthorized)等。
  • 500 Internal Server Error,表示出现了服务器内部错误。5 开头的状态码都是服务器错误状态码。

如果你需要一些示例

我们的浏览器都自带了调试的功能,这是以后会时常用的一个工具。首先打开你的浏览器,我这里是 chrome,右键菜单最下面有一个审查元素,点击打开就会弹出一个窗口,有很多个标签页,有一些以后会用到,点击网络这一个标签页,然后刷新页面就会出现一个类似下面的窗口,可以看到实际产生的网络数据,但是由于实际上发送了很多请求,所以你需要回到最开始的一个请求进行查看。
Python 爬虫教程 2 - HTTP协议
可以看到右边的红色框当中就是我们所关注的部分,即 HTTP 报文。Enjoy Your Trip

参考资料
1. HTTP 权威指南 https://book.douban.com/subject/10746113/