3、静态网页抓取:Requests库入门、GET与POST请求、响应内容解析
说到数据采集,我第一个要跟你聊的就是 Requests 这个库。说实话,Python 里发 HTTP 请求的库不少,但 Requests 是我用得最顺手的。它简洁、直观,几乎不用动脑子就能写出可读性很好的代码。我最早做爬虫的时候用的是 urllib,后来换了 Requests,感觉就像从手动挡换成了自动挡——舒服多了。
3.1 初识 Requests:安装与第一行代码
安装没什么好说的,一行命令搞定:
pip install requests
装完之后,我们来写第一行代码。你想想看,一个最简单的 HTTP 请求长什么样?
import requests
response = requests.get('https://httpbin.org/get')
print(response.status_code)
print(response.text[:200])
就这么几行,你已经完成了一次完整的 GET 请求。我个人习惯在写任何爬虫之前,先用这种简单的请求测试一下目标网站能不能正常响应。如果状态码是 200,说明网络没问题,可以继续往下走。
3.2 GET 与 POST:两种最常用的请求方式
HTTP 协议里有很多请求方法,但做数据采集时,90% 的场景你只会用到 GET 和 POST。我简单说说它们的区别和用法。
3.2.1 GET 请求:拿数据
GET 请求说白了就是「给我看看」。你打开浏览器输入网址,回车的那一瞬间,浏览器就在发 GET 请求。它的特点是参数直接挂在 URL 后面,比如:
import requests
# 带参数的 GET 请求
params = {
'keyword': '数据采集',
'page': 1
}
response = requests.get('https://httpbin.org/get', params=params)
print(response.url) # 看看实际请求的 URL 长什么样
输出结果里你会看到 URL 变成了 https://httpbin.org/get?keyword=数据采集&page=1。这就是 GET 传参的方式——参数暴露在 URL 里,所以千万别用 GET 传密码或敏感信息。
3.2.2 POST 请求:交数据
POST 请求更像是「我提交点东西给你」。参数不会挂在 URL 上,而是放在请求体里。登录、提交表单、上传文件,这些场景基本都是 POST。
import requests
# 带表单数据的 POST 请求
data = {
'username': 'admin',
'password': '123456'
}
response = requests.post('https://httpbin.org/post', data=data)
print(response.json())
我在项目中遇到过好几次这样的坑:明明照着文档写的 POST 请求,但服务器就是不认。后来发现是 Content-Type 没对上。Requests 默认用 application/x-www-form-urlencoded 发表单数据,但如果对方要求 JSON 格式,你得这么写:
import json
# 发送 JSON 格式的 POST 请求
payload = {'key': 'value'}
response = requests.post('https://httpbin.org/post', json=payload)
# 或者手动设置 headers
headers = {'Content-Type': 'application/json'}
response = requests.post('https://httpbin.org/post', data=json.dumps(payload), headers=headers)
data 参数传字典时,Requests 会自动编码成表单格式。用 json 参数时,它会自动设置 Content-Type: application/json 并把字典序列化成 JSON 字符串。别搞混了,否则服务器会给你返回 400 或 415 错误。
3.3 响应内容解析:拿到数据之后怎么办
请求发出去,响应回来了。接下来就是解析响应内容。我一般会先看 status_code,确认请求成功了再往下处理。
| 属性/方法 | 说明 | 常用场景 |
|---|---|---|
response.status_code |
HTTP 状态码 | 判断请求是否成功(200 = 成功) |
response.text |
响应内容(字符串形式) | 解析 HTML、JSON 文本 |
response.content |
响应内容(字节形式) | 下载图片、文件等二进制数据 |
response.json() |
将 JSON 响应解析为字典/列表 | 处理 API 返回的 JSON 数据 |
response.headers |
响应头(字典形式) | 查看 Content-Type、Set-Cookie 等 |
response.encoding |
响应编码 | 解决中文乱码问题 |
举个实际例子。假设我们要抓一个返回 JSON 的 API:
import requests
response = requests.get('https://api.github.com/users/octocat')
if response.status_code == 200:
data = response.json()
print(f"用户名: {data['login']}")
print(f"仓库数: {data['public_repos']}")
else:
print(f"请求失败,状态码: {response.status_code}")
这里有个细节:response.json() 如果遇到非 JSON 格式的内容会抛出异常。所以我一般会在调用之前先确认 Content-Type 是不是 application/json,或者用 try-except 包一下。
3.3.1 处理中文乱码
做中文网站采集时,乱码是个绕不开的问题。我曾经花了一下午排查一个乱码问题,最后发现是网站用了 GBK 编码,而 Requests 默认用 UTF-8 解码。
import requests
response = requests.get('https://example.com')
# 手动设置正确的编码
response.encoding = 'gbk'
print(response.text[:500])
更稳妥的做法是让 Requests 自动从响应头里推断编码:
response.encoding = response.apparent_encoding
apparent_encoding 会基于内容自动检测编码,虽然慢一点,但准确率很高。
status_code,再确认 encoding,最后解析内容。这三步走稳了,80% 的采集问题都不会出现。
3.4 本章知识体系
下面这张图帮你梳理了本章的核心脉络。从安装 Requests 开始,到发出 GET/POST 请求,再到解析响应内容,每一步都有对应的处理方法和常见陷阱。
3.5 避坑指南
做数据采集这几年,我踩过的坑不少。挑几个典型的跟你说说:
- 超时设置:我曾经写过一个采集脚本,没设超时,结果有个请求卡了 20 分钟,整个任务被堵死。从那以后,我每个请求都会加
timeout参数:requests.get(url, timeout=5)。 - User-Agent:有些网站会检查请求头,发现是 Python 的默认 UA 就直接拒绝。我习惯在请求里伪装成浏览器:
headers = {'User-Agent': 'Mozilla/5.0 ...'}。 - 重定向:Requests 默认会自动跟随重定向(301/302)。如果你不想跟,设置
allow_redirects=False。我遇到过一种情况:网站先返回 302 跳转到登录页,自动跟了就抓不到原始数据了。 - Session 保持:如果你需要连续请求(比如先登录再抓数据),用
requests.Session()可以自动保持 Cookie,省去手动管理的麻烦。
嗯,Requests 的基础用法差不多就这些。别觉得简单,很多复杂的采集任务,底层也就是这几行代码的组合。把基础打牢,后面遇到动态页面、API 鉴权、反爬机制的时候,你才能游刃有余。