3、HTTP协议基础:HTTP请求与响应、常见请求头与响应头、GET与POST方法、状态码详解、Session与Cookie机制

做爬虫这么多年,我越来越觉得HTTP协议就是咱们吃饭的碗。碗不结实,饭再香也端不住。很多新手一上来就怼着Scrapy、Selenium猛学,结果连个最简单的反爬都绕不过去。说白了,你连浏览器跟服务器怎么“聊天”的都不清楚,怎么去模拟人家?

这一章,咱们就把HTTP协议扒开揉碎了讲。我保证,看完这章你再去看那些抓包工具里的数据,心里会透亮很多。

3.1 HTTP请求与响应:一次完整的对话

HTTP协议,本质上就是客户端(比如你的浏览器,或者你的爬虫)和服务器之间的一次对话。每次对话都遵循一个固定的模式:客户端先说话(请求),服务器再回答(响应)

我在早期做爬虫时,犯过一个低级错误:以为服务器会主动给客户端推送数据。结果程序跑了一整天,啥也没抓到。后来才明白,HTTP是“请求-响应”模型,服务器永远不会主动理你。

一次完整的HTTP事务包含两个部分:

  • 请求(Request):客户端发给服务器的消息,包含“我要什么”和“我是谁”。
  • 响应(Response):服务器返回给客户端的消息,包含“你要的东西”和“处理结果”。

你想想看,这就像你去餐厅点菜。你喊一声“服务员,来份宫保鸡丁”(请求),服务员回头喊“好嘞,马上来”(响应),然后后厨做好端上来(响应体)。整个过程,你(客户端)永远是发起方。

3.2 常见请求头与响应头:藏在信封里的秘密

HTTP消息的头部,就像信封上的地址和邮戳。服务器通过它来判断你是谁、想干什么。我习惯把请求头比作“身份证”,服务器一看你的身份证不对劲,直接就把你拉黑了。

3.2.1 核心请求头(Request Headers)

请求头名称 含义 爬虫中的坑
User-Agent 告诉服务器你是什么浏览器/设备 不设置或设置成Python默认的,直接封IP
Referer 告诉服务器你从哪个页面跳过来的 很多图片站、防盗链系统就靠它判断
Cookie 携带用户的身份凭证 不带上Cookie,你永远是个“游客”
Accept 告诉服务器你接受什么类型的数据 有些API只返回JSON,你写错了就返回HTML
Content-Type 告诉服务器你发送的数据是什么格式 POST提交表单时,这个头错了服务器不认

我的习惯:写爬虫时,我一般会先复制浏览器里的完整请求头,然后逐个删减测试。删到哪个头导致请求失败,那个头就是关键。大部分情况下,User-AgentRefererCookie这三个是必带的。

3.2.2 核心响应头(Response Headers)

响应头名称 含义 爬虫中的坑
Set-Cookie 服务器让你保存的Cookie 登录成功后,服务器通过它给你发“通行证”
Content-Type 返回的数据类型 判断是HTML、JSON还是图片
Location 重定向地址 302跳转时,爬虫需要自动跟进
Set-Cookie 服务器让你保存的Cookie 登录成功后,服务器通过它给你发“通行证”

嗯,这里要注意:Set-Cookie这个响应头特别重要。我曾经写过一个爬电商的脚本,死活拿不到登录后的数据。抓包一看,服务器返回了Set-Cookie,但我的代码没保存。结果每次请求都像新用户一样,当然拿不到数据。

3.3 GET与POST方法:两种不同的“要法”

GET和POST,是HTTP协议里最常用的两个方法。说白了,就是两种不同的“要数据”的方式。

  • GET:就像你站在图书馆门口,喊一嗓子“我要借《HTTP权威指南》”。所有信息都写在URL里,一目了然。特点是:数据在URL里、有长度限制、会被浏览器缓存、不安全
  • POST:就像你填了一张借书申请表,悄悄递给管理员。数据在请求体里,别人看不到。特点是:数据在请求体里、没有长度限制、不会被缓存、相对安全

爬虫中的选择原则:

  • 获取数据用GET,提交数据用POST。这是铁律。
  • 如果看到浏览器地址栏里有一长串参数,那肯定是GET请求。
  • 如果看到表单提交、登录、上传文件,那肯定是POST请求。

举个例子,你打开百度搜索“爬虫”,浏览器发起的请求就是GET。URL长这样:https://www.baidu.com/s?wd=爬虫。而你在知乎上写回答,点“发布”时,浏览器发起的请求就是POST,你的回答内容藏在请求体里,URL干干净净。

# GET请求示例(Python requests库)
import requests
response = requests.get('https://api.example.com/data?page=1&size=20')
print(response.text)

# POST请求示例
data = {'username': 'admin', 'password': '123456'}
response = requests.post('https://api.example.com/login', data=data)
print(response.text)

避坑指南:我曾经遇到过一个网站,登录页面用的是GET请求。我反复检查代码,确认没错。后来才发现,他们把密码直接放在URL里了。这种设计极其危险,但也说明了一个道理:不要完全相信“POST比GET安全”这句话。真正的安全靠的是HTTPS,而不是请求方法。

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

状态码是服务器给你的“回执”,告诉你这次请求的结果。我习惯把状态码分成五类,就像考试成绩一样:

状态码范围 类别 含义 爬虫中的处理
1xx 信息性 服务器已收到请求,继续处理 很少遇到,直接忽略
2xx 成功 请求成功,数据返回了 200最常见,直接解析数据
3xx 重定向 你需要去另一个地址拿数据 302、301需要自动跟进
4xx 客户端错误 你发的东西有问题 403禁止访问、404找不到、429请求太频繁
5xx 服务器错误 服务器出问题了 500、502、503,等会儿再试

我个人最常打交道的几个状态码:

  • 200 OK:一切正常,数据到手。
  • 301/302 Moved:地址变了。爬虫需要自动跳转,否则拿不到数据。
  • 403 Forbidden:服务器认出你是爬虫了。这时候检查你的请求头,特别是User-AgentCookie
  • 404 Not Found:地址写错了。检查URL拼写。
  • 429 Too Many Requests:你爬太快了,服务器让你歇会儿。这时候需要加延时。
  • 500 Internal Server Error:服务器崩了。不是你的问题,等会儿再试。

我的经验:写爬虫时,一定要先检查状态码。如果返回200但数据是空的,那可能是反爬机制在作怪。如果返回403,别慌,先试试换个User-Agent,不行再加个Referer。我遇到过最奇葩的情况是,一个网站对Accept-Language头有要求,不设置就返回403。

3.5 Session与Cookie机制:服务器怎么记住你?

HTTP协议本身是“无状态”的。什么意思?就是服务器每次收到你的请求,都像第一次见到你一样。它不记得你之前做过什么。

但现实中的网站需要“有状态”。比如你登录淘宝后,再点“我的订单”,服务器得知道你是谁。这就引出了Session和Cookie这对黄金搭档。

  • Cookie:保存在客户端(浏览器)的小数据块。每次请求时,浏览器自动带上它。
  • Session:保存在服务器端的数据。服务器通过Session ID来识别用户。

工作流程是这样的:

  1. 你第一次访问网站,服务器给你一个Set-Cookie响应头,里面有个Session ID。
  2. 你的浏览器保存了这个Cookie。
  3. 你再次访问时,浏览器自动带上这个Cookie。
  4. 服务器根据Cookie里的Session ID,找到对应的Session数据,就知道你是谁了。

爬虫中的Session管理:

在Python的requests库中,使用Session对象可以自动管理Cookie。你只需要登录一次,后续的所有请求都会自动带上登录后的Cookie。

import requests

# 创建一个Session对象
session = requests.Session()

# 第一步:登录
login_data = {'username': 'my_account', 'password': 'my_password'}
session.post('https://example.com/login', data=login_data)

# 第二步:访问需要登录的页面
response = session.get('https://example.com/my_profile')
print(response.text)  # 这里就能拿到登录后的数据了

避坑指南:我曾经写过一个爬虫,手动从浏览器复制了Cookie到代码里。结果第二天Cookie过期了,程序全挂了。后来我改用Session对象,先模拟登录,再爬数据。虽然登录那一步慢了点,但胜在稳定。记住:硬编码Cookie是爬虫的大忌

另外,有些网站会把Session ID放在URL里,而不是Cookie里。这种情况多见于一些老旧的Java网站。遇到这种,你需要从URL里提取Session ID,并在后续请求中带上它。

好了,HTTP协议的基础就讲到这里。下一章咱们聊聊如何用抓包工具把这些理论变成实战。记住,理论是死的,但网站是活的。多抓包、多分析,你自然就能摸清每个网站的脾气。