HTTP协议与网络请求基础
说实话,做数据抓取这么多年,我见过太多人一上来就写爬虫代码,结果被反爬搞得焦头烂额。其实啊,大部分问题都出在没搞懂HTTP协议上。今天咱们就把这块硬骨头啃下来。
核心认知:HTTP协议就是浏览器和服务器之间的「对话规则」。你说话的方式不对,服务器就不搭理你——就这么简单。
HTTP/HTTPS协议原理
HTTP,全称超文本传输协议。说白了,就是客户端(比如你的浏览器)和服务器之间怎么打招呼、怎么传数据的一套规矩。
我个人习惯把HTTP请求想象成「寄快递」:
- 你(客户端)填了个快递单——这就是请求
- 快递员(网络)把单子送到仓库——这就是传输
- 仓库(服务器)收到后给你回个单子——这就是响应
那HTTPS呢?就是给这个快递过程加了个「加密锁」。我在项目中遇到过好几次,抓取HTTP网站时数据包被中间人篡改,后来全换成HTTPS才解决。记住:现在做数据抓取,90%的情况你面对的都是HTTPS。
我的经验:HTTPS的SSL/TLS握手确实会多花几十毫秒,但换来的是数据安全。别为了省这点时间放弃HTTPS,不值得。
请求头与响应头
这是爬虫开发中最容易被忽视、却又最关键的部分。你想想看,服务器怎么知道你是谁?用的什么浏览器?想干什么?全靠请求头里的信息。
我给大家画个图,看看一次完整的HTTP请求长什么样:
关键请求头
| 请求头 | 作用 | 我的建议 |
|---|---|---|
| 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