很多初学爬虫的朋友都会卡在一个点:
页面能看到数据,但用 requests 却抓不到。这类问题 90% 的原因只有一个:数据不是 HTML 直出,而是 Ajax / POST 接口返回的 JSON。
本文将以 汉堡王中国官网 为例,完整演示:
- 如何分析 Ajax 接口
- 如何通过 GET 请求分页爬取所有门店信息
- 如何通过 POST 请求获取产品数据
- 如何用 正则从 JS 中反推参数
- 如何写出健壮、不容易报错的解析逻辑
一、项目目标说明
本次实战分为两个核心目标:
1️⃣ 获取所有门店信息(GET + Ajax)
- 门店名称
- 门店地址
- 门店电话
- 覆盖所有分页数据
2️⃣ 获取产品信息(POST 请求)
- 获取不同产品系列
- 提取每个系列下的产品名称
- 自动发现系列参数,避免手写
二、门店信息爬取:Ajax 接口分析
2.1 页面数据从哪里来?
门店页面地址:
https://www.bkchina.cn/restaurant/index.html
打开浏览器开发者工具 → Network → XHR,你会发现页面并没有直接加载门店 HTML,而是调用了一个 Ajax 接口:
https://www.bkchina.cn/restaurant/getMapsListAjax
核心请求参数包括:
| 参数名 | 说明 |
|---|---|
| page | 页码 |
| storeProvince | 省份 |
| storeCity | 城市 |
| localSelect | 预留参数 |
| search | 搜索关键字 |
👉 这正是爬虫的突破口
2.2 使用 requests 发送 GET 请求
python
import requests
page = 1
count = 1
while True:
url = (
f"https://www.bkchina.cn/restaurant/getMapsListAjax?"
f"page={page}&storeProvince=广东省&storeCity=广州市&localSelect=&search="
)
res = requests.get(url)
res_data = res.json()
这里有一个关键点:
res.text→ 原始字符串res.json()→ 自动转为 Python 字典(并处理 Unicode 中文)
2.3 终止循环的正确方式
接口返回的数据结构大致如下:
python
{
"data": {
"data": [...]
}
}
当所有数据抓取完成后:
python
res_data['data']['data'] == []
所以终止条件可以写成:
python
if not res_data['data']['data']:
break
✅ 这是比 try/except 更稳妥的写法
2.4 解析门店信息(字段清洗)
python
for i in res_data['data']['data']:
storeAddress = i['storeAddress'].replace(" ", "")
storeName = i['storeName']
storePhone = i['storePhone']
print(count, storeName, storeAddress, storePhone)
count += 1
page += 1
📌 小细节很重要:
- 地址中含有
,需要清洗 - 不建议裸
except吃掉异常
三、产品信息爬取:POST 请求入门
3.1 为什么这里是 POST?
产品接口地址:
https://www.bkchina.cn/product/productList
在 Network → Payload 中可以看到:
- 请求方式:POST
- 参数:
type
这类请求参数不会拼在 URL 上,而是放在请求体中。
3.2 单个系列产品获取
python
import requests
url = 'https://www.bkchina.cn/product/productList'
data = {'type': 'season'}
res = requests.post(url, data=data)
res_data = res.json()
返回结果是一个字典,结构类似:
python
{
"季节新品": [
{"FName": "XX 汉堡"},
...
]
}
解析方式:
python
for series, products in res_data.items():
for p in products:
print(p['FName'])
四、批量获取所有产品系列
4.1 手动维护参数(不推荐)
python
types = [
'season', 'ham', 'snack', 'dessert',
'meats', 'coffee', 'breakfirst', 'happy_meal'
]
循环请求即可:
python
for type in types:
res = requests.post(url, data={'type': type})
❌ 问题是:
参数是前端写死在 JS 中的,后期可能会变。
五、进阶技巧:从 JS 中反推参数(强烈推荐)
5.1 参数真正来源
前端 JS 文件:
https://www.bkchina.cn/website/new/js/product.js
我们可以直接请求这个 JS 文件。
5.2 正则提取所有 type 参数
python
import re
import requests
js_url = 'https://www.bkchina.cn/website/new/js/product.js'
res = requests.get(js_url)
res_data_str = res.text
types = re.findall("type = '(.*?)'", res_data_str)[1:]
print(types)
📌 使用 非贪婪匹配 (.*?),避免匹配过多内容。
5.3 自动化爬取所有系列产品
python
for type in types:
res = requests.post(url, data={'type': type})
res_data = res.json()
for k, v in res_data.items():
print('系列名:', k)
if not v:
continue
for y in v:
print(y['FName'])
六、常见坑 & 经验总结
⚠️ 1. data 和 params 不要混用
- GET →
params - POST →
data
⚠️ 2. 字典取值要防 None
python
if v:
for y in v:
...
⚠️ 3. 能不用 try/except 就不用
先判断,再处理,代码更可控
七、总结
通过这个完整案例,你应该已经掌握:
✅ Ajax 接口分析思路
✅ GET 分页爬取技巧
✅ POST 请求参数传递
✅ JSON 数据解析
✅ JS 反向参数提取(核心进阶)
爬虫不是"会 requests 就行",
而是"你能否像前端一样理解数据流向"。
如果这篇文章对你有帮助,
欢迎 点赞 👍 + 收藏 ⭐ + 关注我,后续我会继续拆解更多真实网站的爬虫实战案例 🚀