3. HTTP协议与网络请求:从协议到实战

做数据采集,说白了就是跟HTTP协议打交道。你写的爬虫、调用的API,底层都在走这套规则。我刚开始学爬虫时,总觉得协议是理论课的东西,直到有一次被一个301重定向坑了整整一天……嗯,从那以后我老实了。

今天咱们就把HTTP协议拆开揉碎,看看它到底怎么工作。

3.1 HTTP协议基础:互联网的通用语言

HTTP(HyperText Transfer Protocol)是客户端和服务器之间的通信协议。它定义了请求该怎么发、响应该怎么回。

我个人习惯把HTTP理解成「点餐流程」:

  • 客户端(你)→ 点菜 → 请求
  • 服务器(厨房)→ 出菜 → 响应
  • 状态码 → 比如「菜已售罄」就是404

HTTP有几个核心特点:

  • 无状态:服务器不记得你上次来过。每次请求都是独立的。
  • 明文传输:早期HTTP直接传文本,后来才有了HTTPS加密。
  • 基于TCP/IP:底层靠TCP保证数据不丢包。
我的经验:做采集时,80%的问题出在「无状态」上。比如登录后拿不到数据,多半是没处理好Cookie或Session。我建议新手先抓包看看请求头,比瞎猜快得多。

3.2 请求与响应结构:拆开看看里面有什么

一个HTTP请求长什么样?我直接给你看个例子:

POST /api/login HTTP/1.1
Host: example.com
Content-Type: application/json
User-Agent: Mozilla/5.0
Cookie: session_id=abc123

{"username":"admin","password":"123456"}

结构其实很简单:

  • 请求行:方法 + 路径 + 协议版本
  • 请求头:一堆键值对,告诉服务器你的身份、浏览器、想收什么格式
  • 空行:分隔头和体
  • 请求体:POST/PUT时带的数据,GET没有

响应也是类似的套路:

HTTP/1.1 200 OK
Content-Type: application/json
Set-Cookie: =xyz789; Path=/

{"status":"success","data":{"id":1,"name":"张三"}}
  • 状态行:协议版本 + 状态码 + 状态描述
  • 响应头:服务器返回的元信息
  • 响应体:真正要的数据

关键点:做数据采集时,响应头里的 Content-Type 决定了你怎么解析数据。如果是 application/json 就用JSON解析,text/html 就得用HTML解析器。我见过有人拿JSON解析器去解析HTML,结果全乱码了。

3.3 状态码详解:服务器在说什么

状态码是服务器给你的「暗号」。记住这几类就够了:

分类 范围 含义 常见例子
1xx 100-199 信息性,服务器还在处理 100 Continue
2xx 200-299 成功,请求已处理 200 OK, 201 Created
3xx 300-399 重定向,需要去别处找 301 Moved, 302 Found
4xx 400-499 客户端错误,你发错了 404 Not Found, 403 Forbidden
5xx 500-599 服务器错误,对方崩了 500 Internal Server Error

做采集时,这几个状态码你一定会遇到:

  • 200:一切正常,拿数据就行
  • 301/302:页面搬家了。你的爬虫得跟着跳转,否则拿不到数据
  • 403:被拒绝了。多半是没带Cookie或User-Agent被识别
  • 404:资源不存在。检查URL拼写
  • 429:请求太频繁,被限流了。加延时或换IP
  • 500/502/503:服务器挂了。等会儿再试
避坑指南:我曾经写过一个采集脚本,一直报403。我查了半天,发现是没带 Referer 头。有些网站会检查你是从哪跳转过来的,不带Referer直接拒绝。后来我加上了,问题就解决了。

3.4 常用请求方法:GET、POST、PUT、DELETE

HTTP定义了多种请求方法,但做数据采集最常用的就这四个:

方法 作用 有无请求体 幂等性 典型场景
GET 获取资源 无 是 浏览网页、查询数据
POST 创建资源 有 否 提交表单、登录
PUT 更新资源 有 是 修改用户信息
DELETE 删除资源 通常无 是 删除文章

GET 是最常用的。参数拼在URL里,比如 ?page=1&size=20。我建议你注意两点:

  • URL长度有限制(不同浏览器不一样,一般2048字符以内)
  • 敏感信息别放URL里,会暴露

POST 是采集的利器。参数放请求体里,可以传大量数据。常见的格式有:

  • application/x-www-form-urlencoded:表单格式,key=value&key2=value2
  • application/json:JSON格式,现在最常用
  • multipart/form-data:传文件时用

PUT 和 DELETE 在RESTful API里很常见。做采集时,如果遇到需要修改或删除数据的场景,就会用到它们。

实战建议:我个人习惯用Python的 requests 库。发GET请求就一行 requests.get(url),POST就 requests.post(url, json=data)。但要注意,有些网站会检查 User-Agent,我一般会设置成浏览器的样子:

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    'Referer': 'https://example.com'
}
response = requests.get(url, headers=headers)

3.5 知识结构总览

下面这张图把HTTP协议的核心知识点串起来了。你想想看,从请求到响应,每一步都有对应的规则:

HTTP协议知识结构图 HTTP协议知识结构 客户端(爬虫) 请求方法 GET / POST PUT / DELETE 请求结构 请求行 + 请求头 空行 + 请求体 服务器 状态码 2xx 成功 4xx 客户端错误 响应结构 状态行 + 响应头 空行 + 响应体 HTTP请求 HTTP响应 核心:请求 → 处理 → 响应,每一步都有规范

3.6 实战中的坑与技巧

最后分享几个我踩过的坑,希望能帮你少走弯路:

  • 重定向陷阱:有些网站用302跳转到登录页。你的爬虫如果不自动跟进,就会一直拿到登录页的HTML。我建议用 requests 时设置 allow_redirects=True。
  • 编码问题:响应头里的 charset 可能和实际内容不一致。我习惯用 response.apparent_encoding 自动检测编码。
  • 超时设置:别让爬虫无限等待。我一般设 timeout=10,超过10秒就重试。
  • 限流应对:遇到429状态码,先停一下。我常用的策略是「指数退避」——第一次等1秒,第二次等2秒,第三次等4秒,以此类推。

小技巧:调试HTTP请求时,我推荐用 curl 命令先试一下。比如:

curl -v -X POST https://api.example.com/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"123"}'

这样能看到完整的请求和响应,比在代码里调试直观多了。

HTTP协议看起来简单,但细节很多。你只要把请求结构、状态码、常用方法这三块吃透,数据采集的基础就算打牢了。剩下的就是多写多练,遇到问题别慌,抓包看看,多半能找到原因。