学爬虫,80% 的问题都出在「请求没发对」或「响应不会解析」。
本文从 requests 请求方式、中文参数、响应解析、JSON 处理、多层嵌套、分页控制 等核心点出发,系统梳理 Python 爬虫中最容易踩坑、但也最重要的一整套逻辑。
一、爬虫的本质:请求 → 响应
爬虫不是"抓网页",而是"模拟浏览器发请求"。
浏览器做的事情只有两步:
1️⃣ 向服务器发送请求(Request)
2️⃣ 接收服务器返回的响应(Response)
Python 爬虫,本质上就是把这两步程序化、自动化。
二、GET 请求的两种参数传递方式(必考)
方式一:URL 直接拼接参数(最直观)
python
url = "https://www.xxx.com/search?q=胃炎&page=1"
res = requests.get(url)
特点:
- 和浏览器地址栏一模一样
- 简单、直观
- 参数一多就很乱,不利于维护
方式二:使用 params 字典传参(强烈推荐)
python
url = "https://www.xxx.com/search"
params = {
"q": "胃炎",
"page": 1
}
res = requests.get(url, params=params)
优势:
- 结构清晰
- 易于调试和修改
- requests 会自动帮你处理 URL 编码
📌 重要技巧
requests.get(url, params) 中,params 是第二个默认参数,参数名可省略。
三、中文参数 & URL 编码的坑(高频翻车点)
1️⃣ 浏览器 vs Python 的本质区别
-
浏览器地址栏:
👉 显示中文
👉 实际发送的是
%E8%83%83%E7%82%8E -
Python requests:
👉 字典传参时,不能手动写编码
👉 直接用中文即可
❌ 错误示例:
python
params = {"q": "%E8%83%83%E7%82%8E"} # 很容易请求失败
✅ 正确写法:
python
params = {"q": "胃炎"}
📌 结论一句话记住:
URL 编码只适用于 URL 字符串,不适用于 params 字典。
四、响应内容的三种获取方式
1️⃣ res.text ------ 文本内容(HTML / 普通文本)
-
返回类型:
str -
适用场景:
- 搜索结果页
- 医疗问答页
- HTML 页面
python
html = res.text
⚠️ 注意:
res.text 哪怕长得像字典,也还是字符串 ,不能直接 ['key'] 取值。
2️⃣ res.content ------ 二进制数据
- 图片 / 视频 / 音频
- 用于下载文件
python
img_bytes = res.content
3️⃣ res.json() ------ JSON 数据(最香)
python
data = res.json()
前提条件只有一个:
响应内容必须是标准的列表或字典结构
✅ 典型特征:
json
{
"Code": 200,
"Data": {
"Posts": [...]
}
}
❌ 不能用 .json() 的情况:
- HTML 页面
- 含
<div>、<span>的文本页面
五、为什么 res.text 很难用?
因为它只是一个字符串:
python
type(res.text) # <class 'str'>
你会遇到这些问题:
- 不能按 key 取值
- 不能处理嵌套结构
- 遇到 HTML 标签只能用字符串 / 正则
📌 结论:
能用
.json(),坚决不用.text
六、多层 JSON 嵌套解析:像"剥洋葱"
以招聘接口为例,典型结构如下:
字典
└── Data(字典)
└── Posts(列表)
└── 每一项(字典)
取值路径示例:
python
res_data['Data']['Posts'][0]['RecruitPostName']
📌 两个核心规则:
- 字典 → 用 key
- 列表 → 用索引 / for 循环
七、循环解析数据:for vs while
1️⃣ for 循环(最推荐)
python
for post in res_data['Data']['Posts']:
print(post['RecruitPostName'])
优点:
- 不用管索引
- 不会越界
- 代码简洁、安全
2️⃣ while 循环(需要你非常清醒)
python
i = 0
while i < len(posts):
print(posts[i])
i += 1
⚠️ 极易犯错:
- 忘记
i += 1 - 条件写错 → 死循环
八、分页爬取:爬虫的灵魂能力
1️⃣ 固定页数(for 循环)
python
for page in range(1, 11):
params['pageIndex'] = page
缺点:
- 页数一变,代码就废
2️⃣ 动态分页(while True,企业级写法)
python
page = 1
while True:
params['pageIndex'] = page
res = requests.get(url, params=params)
data = res.json()
posts = data['Data']['Posts']
if posts is None:
break
for post in posts:
print(post['RecruitPostName'])
page += 1
📌 结束循环的黄金写法:
python
if not posts:
break
九、请求头 headers:绕过反爬的第一道门
1️⃣ 为什么一定要加 User-Agent?
服务器会判断:
"你是不是浏览器?"
不加请求头 = 高概率返回假数据 / 空数据
2️⃣ 正确写法(注意参数名)
python
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
}
res = requests.get(url, headers=headers)
❌ 错误写法:
python
requests.get(url, headers_dict) # 会被当成 params
十、JSONDecodeError:90% 新手都会遇到
出现原因:
- 被反爬
- 返回 HTML 而不是 JSON
- 请求参数错误
排查思路:
1️⃣ 打印 res.text
2️⃣ 对比浏览器响应
3️⃣ 补齐 headers
4️⃣ 降低请求频率
十一、核心思维总结(比代码更重要)
爬虫不是记代码,而是记逻辑
所有网站,套路只有这一套:
1️⃣ 找接口
2️⃣ 发请求
3️⃣ 判断响应类型
4️⃣ 解析数据结构
5️⃣ 设计循环
6️⃣ 处理分页
7️⃣ 控制退出条件
代码会变,逻辑不变。
十二、写给初学者的一句话建议
学会一套完整流程,比背 100 段爬虫代码更重要。
如果你把本文内容真正敲一遍、跑一遍,你已经超过 80% 的爬虫初学者。
📌 如果这篇文章对你有帮助,欢迎点赞 + 收藏 + 关注
后续我会继续拆解:
👉 反爬策略
👉 Cookie / Session
👉 字段清洗与存储
👉 企业级爬虫结构设计