学爬虫,80% 的问题都出在「请求没发对」或「响应不会解析」。
本文从requests 请求方式、中文参数、响应解析、JSON 处理、多层嵌套、分页控制等核心点出发,系统梳理 Python 爬虫中最容易踩坑、但也最重要的一整套逻辑。
一、爬虫的本质:请求 → 响应
爬虫不是“抓网页”,而是“模拟浏览器发请求”。
浏览器做的事情只有两步:
1️⃣ 向服务器发送请求(Request)
2️⃣ 接收服务器返回的响应(Response)
Python 爬虫,本质上就是把这两步程序化、自动化。
二、GET 请求的两种参数传递方式(必考)
方式一:URL 直接拼接参数(最直观)
url="https://www.xxx.com/search?q=胃炎&page=1"res=requests.get(url)特点:
- 和浏览器地址栏一模一样
- 简单、直观
- 参数一多就很乱,不利于维护
方式二:使用 params 字典传参(强烈推荐)
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%8EPython requests:
👉字典传参时,不能手动写编码
👉 直接用中文即可
❌ 错误示例:
params={"q":"%E8%83%83%E7%82%8E"}# 很容易请求失败✅ 正确写法:
params={"q":"胃炎"}📌结论一句话记住:
URL 编码只适用于 URL 字符串,不适用于 params 字典。
四、响应内容的三种获取方式
1️⃣res.text—— 文本内容(HTML / 普通文本)
返回类型:
str适用场景:
- 搜索结果页
- 医疗问答页
- HTML 页面
html=res.text⚠️ 注意:res.text哪怕长得像字典,也还是字符串,不能直接['key']取值。
2️⃣res.content—— 二进制数据
- 图片 / 视频 / 音频
- 用于下载文件
img_bytes=res.content3️⃣res.json()—— JSON 数据(最香)
data=res.json()前提条件只有一个:
响应内容必须是标准的列表或字典结构
✅ 典型特征:
{"Code":200,"Data":{"Posts":[...]}}❌ 不能用.json()的情况:
- HTML 页面
- 含
<div>、<span>的文本页面
五、为什么 res.text 很难用?
因为它只是一个字符串:
type(res.text)# <class 'str'>你会遇到这些问题:
- 不能按 key 取值
- 不能处理嵌套结构
- 遇到 HTML 标签只能用字符串 / 正则
📌结论:
能用
.json(),坚决不用.text
六、多层 JSON 嵌套解析:像“剥洋葱”
以招聘接口为例,典型结构如下:
字典 └── Data(字典) └── Posts(列表) └── 每一项(字典)取值路径示例:
res_data['Data']['Posts'][0]['RecruitPostName']📌 两个核心规则:
- 字典 → 用 key
- 列表 → 用索引 / for 循环
七、循环解析数据:for vs while
1️⃣ for 循环(最推荐)
forpostinres_data['Data']['Posts']:print(post['RecruitPostName'])优点:
- 不用管索引
- 不会越界
- 代码简洁、安全
2️⃣ while 循环(需要你非常清醒)
i=0whilei<len(posts):print(posts[i])i+=1⚠️ 极易犯错:
- 忘记
i += 1 - 条件写错 → 死循环
八、分页爬取:爬虫的灵魂能力
1️⃣ 固定页数(for 循环)
forpageinrange(1,11):params['pageIndex']=page缺点:
- 页数一变,代码就废
2️⃣ 动态分页(while True,企业级写法)
page=1whileTrue:params['pageIndex']=page res=requests.get(url,params=params)data=res.json()posts=data['Data']['Posts']ifpostsisNone:breakforpostinposts:print(post['RecruitPostName'])page+=1📌结束循环的黄金写法:
ifnotposts:break九、请求头 headers:绕过反爬的第一道门
1️⃣ 为什么一定要加 User-Agent?
服务器会判断:
“你是不是浏览器?”
不加请求头 =高概率返回假数据 / 空数据
2️⃣ 正确写法(注意参数名)
headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}res=requests.get(url,headers=headers)❌ 错误写法:
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
👉 字段清洗与存储
👉 企业级爬虫结构设计