3. HTTP协议与网络请求:数据采集的“交通规则”
做数据采集,说白了就是跟HTTP协议打交道。你写的爬虫、调用的API,底层都在走HTTP。我刚开始接触这行时,觉得协议这东西太理论,结果第一次写爬虫就被反爬搞懵了——后来才发现,很多问题都是因为没吃透HTTP。
这一章,咱们就把HTTP/HTTPS协议、请求方法、头信息、状态码、Cookie和Session这些核心概念,一个一个掰开揉碎。嗯,都是实战中天天用的东西。
核心观点:HTTP协议是数据采集的“语言”。不懂协议,你连服务器在说什么都听不懂,更别说采集数据了。
3.1 HTTP/HTTPS协议基础
HTTP,全称超文本传输协议。它定义了客户端和服务器之间怎么说话。你想想看,你在浏览器里输入一个网址,背后就是浏览器作为客户端,向服务器发了一条HTTP请求。
HTTPS呢?就是HTTP的加密版本。我在项目中遇到过好几次,采集明文HTTP接口时,数据包被中间人篡改,拿到的数据全是乱码。后来全部切到HTTPS,问题就解决了。
| 特性 | HTTP | HTTPS |
|---|---|---|
| 端口 | 80 | 443 |
| 加密 | 明文传输 | TLS/SSL加密 |
| 安全性 | 低,易被窃听 | 高,防篡改防窃听 |
| 证书 | 不需要 | 需要CA证书 |
| 性能 | 较快 | 略慢(握手开销) |
我的建议:现在做数据采集,能走HTTPS尽量走HTTPS。虽然握手慢一点,但数据完整性有保障。我曾经因为偷懒用HTTP,结果采集到的数据被运营商插入了广告代码,排查了一整天。
3.2 请求方法:GET与POST
HTTP定义了多种请求方法。但做数据采集,你最常用的就两个:GET和POST。
GET请求
GET是用来获取资源的。参数拼在URL后面,用问号分隔。说白了,就是“你给我这个数据”。
# GET请求示例
GET /api/users?id=123&page=1 HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
我在项目中遇到过一个问题:采集一个分页列表,用GET传page参数,结果URL太长被服务器截断了。后来发现是参数里带了大量筛选条件。嗯,这时候就要考虑用POST了。
POST请求
POST通常用来提交数据。参数放在请求体里,不会暴露在URL中。适合传大量数据或敏感信息。
# POST请求示例
POST /api/login HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: 45
{"username": "admin", "password": "123456"}
| 对比项 | GET | POST |
|---|---|---|
| 数据位置 | URL参数 | 请求体 |
| 数据长度 | 有限制(浏览器/服务器限制) | 理论上无限制 |
| 安全性 | 低,参数可见 | 较高,参数在体中 |
| 幂等性 | 是(多次请求结果相同) | 否(可能改变服务器状态) |
| 缓存 | 可被缓存 | 一般不缓存 |
避坑指南:我曾经写过一个爬虫,用GET请求提交登录表单,结果密码直接暴露在服务器日志里。后来被安全团队通报了。记住:涉及敏感信息,永远用POST。
3.3 请求头与响应头
HTTP头信息,是客户端和服务器互相传递的“元数据”。你想想看,就像寄快递时填的快递单——收件人、寄件人、包裹类型、重量,都在单子上。
常见请求头
- Host:目标服务器域名。必须的,没有它服务器不知道你要访问哪个站点。
- User-Agent:客户端身份标识。我建议你采集时一定要伪装这个,很多反爬就靠它。
- Referer:来源页面。有些API会校验这个,防止跨站请求。
- Cookie:携带的会话信息。后面会细讲。
- Content-Type:请求体的数据格式。比如application/json、application/x-www-form-urlencoded。
- Authorization:认证信息。Bearer token或Basic auth常用。
常见响应头
- Content-Type:响应体的数据类型。text/html、application/json等。
- Set-Cookie:服务器要求客户端设置的Cookie。
- Cache-Control:缓存策略。no-cache表示不缓存。
- Location:重定向目标URL。配合301/302状态码使用。
- Access-Control-Allow-Origin:CORS跨域设置。采集时经常遇到。
# 一个完整的请求-响应示例
# 请求
GET /api/data HTTP/1.1
Host: api.example.com
User-Agent: MyCrawler/1.0
Accept: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
# 响应
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Cache-Control: no-cache
Set-Cookie: session_id=abc123; Path=/
{"status": "success", "data": [...]}
我的经验:采集时如果遇到403或406错误,八成是请求头没配好。我习惯先抓包看浏览器正常请求的头信息,然后照搬。特别是User-Agent和Referer,这两个最容易出问题。
3.4 状态码详解
状态码是服务器给你的“回执”。看到不同的状态码,你就知道接下来该怎么做。
| 状态码 | 含义 | 采集时的处理 |
|---|---|---|
| 200 | 请求成功 | 正常解析响应体 |
| 301/302 | 重定向 | 跟进Location头,重新请求 |
| 400 | 请求参数错误 | 检查参数格式和必填项 |
| 401 | 未认证 | 检查Token或认证信息 |
| 403 | 禁止访问 | 被反爬了,换IP或加头 |
| 404 | 资源不存在 | 检查URL路径是否正确 |
| 429 | 请求过多 | 限流了,加延时重试 |
| 500 | 服务器内部错误 | 等一会儿重试,或联系管理员 |
| 502/503 | 服务不可用 | 服务器挂了,稍后再试 |
避坑指南:我曾经遇到一个接口,偶尔返回200但响应体是空的。一开始以为是bug,后来发现是服务器在限流时返回了200空体。所以,别只看状态码,还要检查响应体内容。
3.5 Cookie与Session
HTTP是无状态的。服务器记不住你。那怎么实现“登录后保持状态”呢?靠Cookie和Session。
Cookie
Cookie是存储在客户端的小数据块。服务器通过Set-Cookie响应头告诉浏览器存什么,浏览器下次请求时自动带上。
# 服务器设置Cookie
Set-Cookie: session_id=abc123; Domain=.example.com; Path=/; HttpOnly; Secure
# 客户端后续请求自动携带
Cookie: session_id=abc123
Cookie的属性很重要:
- Domain/Path:限定Cookie的作用范围。
- Expires/Max-Age:过期时间。不设置就是会话Cookie,关浏览器就没了。
- HttpOnly:禁止JavaScript读取。防XSS攻击。
- Secure:仅HTTPS下传输。
- SameSite:防CSRF攻击。Lax、Strict、None三种模式。
Session
Session是存储在服务器端的数据。服务器生成一个唯一的Session ID,通过Cookie发给客户端。客户端下次请求时带上这个ID,服务器就能找到对应的Session数据。
说白了,Cookie是“通行证”,Session是“档案室”。通行证上只写了个编号,真正的数据存在档案室里。
采集要点:模拟登录时,核心就是拿到Cookie中的Session ID。我建议你用requests.Session()来自动管理Cookie,省得手动处理。但要注意,有些站点会校验User-Agent和IP的一致性,换了IP可能Session就失效了。
# Python示例:使用Session自动管理Cookie
import requests
session = requests.Session()
# 第一次请求:登录
login_data = {"username": "admin", "password": "123456"}
resp = session.post("https://example.com/login", data=login_data)
# 此时session对象已经自动保存了服务器返回的Cookie
# 后续请求:自动携带Cookie
data = session.get("https://example.com/api/data").json()
print(data)
Cookie与Session的对比
| 对比项 | Cookie | Session |
|---|---|---|
| 存储位置 | 客户端(浏览器) | 服务器端 |
| 存储容量 | 有限(一般4KB) | 理论上无限制 |
| 安全性 | 较低,可被篡改 | 较高,数据在服务端 |
| 生命周期 | 由Expires控制 | 由服务器配置控制 |
| 依赖关系 | 独立存在 | 通常依赖Cookie传递Session ID |
我的习惯:采集需要登录的站点时,我会先用浏览器手动登录,然后从开发者工具里把Cookie复制出来,写到代码里。这样能避免登录逻辑的复杂性。但要注意Cookie会过期,需要定期刷新。
嗯,HTTP协议这块内容不少,但都是数据采集的基石。你把这些搞懂了,后面写爬虫、调API就会顺手很多。记住:协议是死的,但应用是活的。多抓包、多分析,慢慢就有感觉了。