Python 爬虫实战:从 Ajax 到 POST 请求,完整爬取汉堡王门店与产品数据

很多初学爬虫的朋友都会卡在一个点:
页面能看到数据,但用 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 就行",
而是"你能否像前端一样理解数据流向"。


如果这篇文章对你有帮助,

欢迎 点赞 👍 + 收藏 ⭐ + 关注我,后续我会继续拆解更多真实网站的爬虫实战案例 🚀

相关推荐
卷无止境19 分钟前
写代码这件事,到底该讲究点什么?
后端·python
卷无止境26 分钟前
循环复杂度到底在算什么,Python 代码怎么才能写得让人一看就懂
后端·python
lpfasd12329 分钟前
MediaCrawler 项目深度分析
chrome·python·chrome devtools
Dxy12393102161 小时前
Python项目打包成EXE完整教程(PyInstaller实战避坑)
开发语言·python
bamb002 小时前
一个项目带你入门AI应用开发01
python
0566462 小时前
Python康复训练——常用标准库
开发语言·python·学习
hyf3266332 小时前
泛程序:从零开始搭建稳定程序项目框架
运维·服务器·爬虫·百度·seo
昆曲之源_娄江河畔2 小时前
Python如何安装flask, pymssql
开发语言·python·flask·pymssql
0566462 小时前
Python康复训练——控制流与函数
开发语言·python·学习
天使day3 小时前
FastAPI快速入门
python·fastapi