HTTP协议与网络请求基础

说实话,做数据抓取这么多年,我见过太多人一上来就写爬虫代码,结果被反爬搞得焦头烂额。其实啊,大部分问题都出在没搞懂HTTP协议上。今天咱们就把这块硬骨头啃下来。

核心认知:HTTP协议就是浏览器和服务器之间的「对话规则」。你说话的方式不对,服务器就不搭理你——就这么简单。

HTTP/HTTPS协议原理

HTTP,全称超文本传输协议。说白了,就是客户端(比如你的浏览器)和服务器之间怎么打招呼、怎么传数据的一套规矩。

我个人习惯把HTTP请求想象成「寄快递」:

  • 你(客户端)填了个快递单——这就是请求
  • 快递员(网络)把单子送到仓库——这就是传输
  • 仓库(服务器)收到后给你回个单子——这就是响应

那HTTPS呢?就是给这个快递过程加了个「加密锁」。我在项目中遇到过好几次,抓取HTTP网站时数据包被中间人篡改,后来全换成HTTPS才解决。记住:现在做数据抓取,90%的情况你面对的都是HTTPS

我的经验:HTTPS的SSL/TLS握手确实会多花几十毫秒,但换来的是数据安全。别为了省这点时间放弃HTTPS,不值得。

请求头与响应头

这是爬虫开发中最容易被忽视、却又最关键的部分。你想想看,服务器怎么知道你是谁?用的什么浏览器?想干什么?全靠请求头里的信息。

我给大家画个图,看看一次完整的HTTP请求长什么样:

客户端(你的代码) 服务器 请求(含请求头) 响应(含响应头) GET /api/data HTTP/1.1 Host: example.com User-Agent: Mozilla/5.0 ... Cookie: session_id=abc123 HTTP/1.1 200 OK Content-Type: application/json Set-Cookie: token=xyz789 Content-Length: 1024

关键请求头

请求头 作用 我的建议
User-Agent 告诉服务器你是什么浏览器 一定要伪装成真实浏览器,别用Python默认的
Cookie 携带登录状态或会话信息 抓取需要登录的数据时,这个最关键
Referer 告诉服务器你从哪个页面跳过来的 很多网站会检查这个,少了就拒绝你
Authorization 携带认证令牌 API接口常用,Bearer token格式

避坑指南:我曾经因为没加Referer头,被一个电商网站封了三天IP。后来发现人家就靠这个判断是不是正常访问。所以啊,请求头能模仿多像就模仿多像。

状态码详解

服务器给你的响应里,第一行就是状态码。这玩意儿就像服务器的「表情包」——一看就知道它开不开心。

我按类别给大家捋一捋:

状态码 含义 实际场景
200 请求成功 数据正常返回,最理想的情况
301/302 重定向 网址变了,requests默认会自动跟随
403 禁止访问 被反爬了,检查请求头或IP
404 资源不存在 URL写错了,或者内容被删了
429 请求太频繁 触发了频率限制,赶紧加延时
500 服务器内部错误 不是你的问题,等会儿再试
502/503 服务器暂时不可用 网站挂了或者维护中

我的习惯:写爬虫时,我会先打印状态码看看。如果是403或429,立马停手检查——别傻乎乎地继续发请求,IP被封了更麻烦。

使用requests库发送请求

好了,理论说完了,咱们上手写代码。Python的requests库,我用它抓过几百万条数据,稳得很。

基础GET请求

import requests

# 最基本的请求
url = "https://api.example.com/posts"
response = requests.get(url)

# 看看结果
print(response.status_code)  # 200 就对了
print(response.text)         # 返回的文本内容
print(response.json())       # 如果是JSON,直接解析

带请求头的请求

这才是实战中的标准写法。我每次写爬虫,第一件事就是配请求头:

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    "Referer": "https://example.com/",
    "Cookie": "session=your_cookie_here"
}

response = requests.get(url, headers=headers)

重点:headers参数一定要用字典传。我见过有人直接写字符串,结果服务器根本不认。

POST请求与表单数据

登录、提交数据时用POST。说白了就是给服务器「递纸条」:

# 表单数据
data = {
    "username": "admin",
    "password": "123456"
}

response = requests.post("https://example.com/login", data=data)

# 如果是JSON格式
json_data = {"key": "value"}
response = requests.post("https://api.example.com/data", json=json_data)

处理超时和异常

嗯,这里要注意。网络请求随时可能出问题,不加超时的话,代码可能卡死:

try:
    response = requests.get(url, timeout=5)  # 5秒超时
    response.raise_for_status()  # 状态码不是200就抛异常
except requests.exceptions.Timeout:
    print("请求超时了,换个代理试试")
except requests.exceptions.HTTPError as e:
    print(f"HTTP错误:{e}")
except Exception as e:
    print(f"其他错误:{e}")

血的教训:我曾经没设timeout,结果有个请求卡了20分钟。从那以后,我所有请求都加timeout,最多等10秒。

Session会话保持

如果你需要连续请求(比如先登录再抓数据),用Session对象。它会自动帮你管理Cookie:

session = requests.Session()

# 先登录
session.post("https://example.com/login", data={"user": "admin", "pass": "123"})

# 再抓数据——Cookie自动带上
response = session.get("https://example.com/profile")
print(response.text)

我个人习惯把所有请求都通过Session发,省得手动维护Cookie,省心。

小技巧:用Session时,可以设置默认headers,这样每次请求不用重复写:

session = requests.Session()
session.headers.update({"User-Agent": "Mozilla/5.0"})
# 之后所有session.get/post都会自动带上这个头

好了,HTTP协议这块咱们就聊到这儿。记住一句话:爬虫的本质就是模拟浏览器发请求。你把请求头配得像真的,把状态码理解透了,用requests库顺手了——数据抓取就成功了一半。


公众号:蓝海资料掘金营,微信deep3321