实战解析:如何利用Python爬虫精准抓取肯德基全国门店数据
1. 从零开始:为什么我们需要抓取肯德基门店数据?
你可能觉得,想知道哪里有肯德基,打开地图App搜一下不就行了?确实,对于个人来说,这完全够用。但如果你是一个市场分析师、一个准备开店的创业者,或者是一个需要研究连锁品牌布局策略的研究者,情况就完全不同了。你需要的是批量、精准、结构化的数据。
想象一下,你需要分析肯德基在全国各个城市的门店密度,研究它在不同商圈(比如火车站、商业中心、社区)的选址偏好,或者对比它和竞争对手的门店分布。手动在地图上一个个点开、记录,不仅效率低下,而且无法进行后续的数据分析。这时候,Python爬虫技术就成了你的“数据收割机”。
我几年前接手过一个项目,客户想在某三线城市的核心商圈开一家快餐店,需要评估竞争环境。我们团队最初也是手动收集信息,花了整整两天,眼睛都看花了,数据还零零散散。后来我用爬虫写了个脚本,不到半小时就把周边几个主要快餐品牌(包括肯德基)的所有门店地址、甚至部分公开的营业信息都抓取了下来,直接生成了可视化地图和数据分析报告。那一刻,我深刻体会到自动化工具带来的效率革命。
所以,今天我们就来手把手拆解,如何用Python爬虫,精准地抓取肯德基全国的餐厅数据。整个过程,我会把我踩过的坑、总结的技巧都分享给你,保证你跟着做一遍就能上手。我们不会涉及任何复杂、高深的技术,就用最基础的 requests 库,核心是教会你分析网络请求的思路,这个思路学会了,抓取很多其他网站的数据也会触类旁通。
2. 核心第一步:找到数据真正的“家门”
很多新手学爬虫,一上来就急着写代码,结果往往碰一鼻子灰。我的经验是,七分靠分析,三分靠编码。数据在哪?网站用什么方式把数据给到前端的?搞清楚这些,代码就是水到渠成的事情。
我们这次的目标网站是肯德基中国的餐厅查询页面:https://www.kfc.com.cn/kfccda/index.aspx。打开这个页面,你会看到餐厅查询的入口。
关键操作来了:
- 在查询框里输入“北京”,点击查询按钮。
- 仔细观察浏览器地址栏的URL,它变了吗?
你会发现,URL根本没变,还是原来那个。但页面下方却实实在在地显示出了北京的餐厅列表。这就是一个典型的线索:数据是通过Ajax技术动态加载的。整个页面没有刷新,只是局部更新了餐厅列表那块区域。这意味着,餐厅数据不是直接写在最初的网页HTML代码里的,而是浏览器在后台悄悄向服务器又发了一个请求,拿到数据后再“画”到页面上的。
我们的任务,就是找到浏览器偷偷发的这个请求。这里就需要请出开发者工具了(按F12打开)。切换到 Network(网络) 面板,记得先清空一下记录(点击那个红色的禁止图标或按Ctrl+R刷新页面)。然后,再次在页面输入“北京”并点击查询。
这时,Network面板里会刷出一堆新的请求记录。怎么找我们需要的那个呢?有个技巧:点击面板上方的 XHR 或 Fetch 筛选按钮。因为Ajax请求通常属于这两种类型。筛选后,列表会清爽很多,通常只剩下几个请求。
接下来,我们需要在剩下的请求里,找到那个“携带”着餐厅数据的请求。怎么看呢?一个个点开,主要看两个地方:
- Preview(预览) 或 Response(响应) 标签页:这里会直接显示服务器返回的数据。如果你点开一个请求,在这里看到了包含餐厅名称、地址的JSON格式数据,那恭喜你,找到正主了!
- Headers(请求头) 标签页:这里记录了请求的详细信息,比如请求的URL、请求方法(GET还是POST)、以及携带了哪些参数。
以肯德基这个网站为例,我们很容易就能找到一个名为 GetStoreList.ashx?op=keyword 的请求。点开它的 Response,熟悉的餐厅信息就在眼前。再点开 Headers,往下翻到 Form Data 或 Payload 部分,能看到它提交给服务器的参数:
cname:
pid:
keyword: 北京
pageIndex: 1
pageSize: 10
看,keyword 就是我们输入的“北京”,pageIndex 是页码,pageSize 是每页显示的数量。这些参数,就是我们要在代码里模拟提交的东西。找到这个请求的URL(在Headers的General部分)和这些参数,我们爬虫最核心、最困难的一步——逆向分析——就完成了。剩下的,就是按照这个“配方”,让我们的Python程序去模拟这个请求。
3. 动手搭建爬虫:从单次请求到批量抓取
分析工作完成后,写代码反而成了相对简单的一步。我们使用Python中最常用的网络请求库:requests。如果你还没安装,在命令行里输入 pip install requests 就能搞定。
3.1 构建你的第一个请求
我们先来复现刚才分析到的那个请求,抓取“北京”第一页的数据。
import requests
# 1. 指定目标URL(就是我们在开发者工具里找到的那个地址)
url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'
# 2. 准备请求参数(模拟表单提交的数据)
data = {
'cname': '', # 观察发现这两个字段常为空,我们也留空
'pid': '',
'keyword': '北京', # 要查询的城市
'pageIndex': '1', # 查询第几页
'pageSize': '10', # 每页数量,网站固定为10
}
# 3. 设置请求头,进行简单的UA伪装
# 这相当于给我们的程序戴了个“面具”,让它看起来更像一个普通的浏览器
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
# 4. 发送POST请求
response = requests.post(url=url, data=data, headers=headers)
# 5. 打印响应内容
print(response.text)
把这段代码保存为 kfc_spider.py 并运行,你应该能在控制台看到一串JSON格式的文本,里面就包含了北京地区第一页的10家肯德基餐厅信息,比如店名、地址、餐厅详情页链接等。恭喜,你的爬虫已经成功迈出了第一步!
3.2 处理数据:从JSON到结构化表格
直接打印出来的JSON字符串不方便阅读和分析。我们需要用Python的 json 库把它解析成字典或列表,然后提取出我们关心的字段。
import json
# ... 前面的请求代码 ...
# 假设 response 是上面请求得到的响应对象
if response.status_code == 200: # 确保请求成功
# 将响应的文本解析为Python字典
result_dict = json.loads(response.text)
# 查看这个字典的结构,找到存放餐厅列表的键
# 通常可以通过打印 result_dict 的键名,或者直接查看之前的Response预览来确定
# 根据观察,肯德基返回的数据中,餐厅列表在 'Table1' 这个键下
store_list = result_dict.get('Table1', [])
for store in store_list:
# 提取我们需要的信息,字段名需要根据实际返回的JSON来确定
store_name = store.get('storeName', 'N/A')
address_detail = store.get('addressDetail', 'N/A')
city_name = store.get('cityName', 'N/A')
print(f"城市:{city_name} | 店名:{store_name} | 地址:{address_detail}")
else:
print(f"请求失败,状态码:{response.status_code}")
运行这段代码,你就能看到整洁排列的餐厅信息了。不过,打印在屏幕上还不是终点,我们需要把它保存下来。
3.3 持久化存储:选择适合你的方式
保存数据有多种方式,对于初学者,我推荐两种最实用的:
方法一:保存为CSV文件 CSV(逗号分隔值)文件可以用Excel直接打开,进行排序、筛选,非常方便后续分析。
import csv
# ... 前面的请求和解析代码 ...
# 假设我们已经得到了 store_list
filename = 'kfc_beijing_page1.csv'
with open(filename, 'w', newline='', encoding='utf-8-sig') as f: # 注意编码用utf-8-sig支持Excel中文
writer = csv.writer(f)
# 先写入表头
writer.writerow(['城市', '店名', '详细地址'])
# 再逐行写入数据
for store in store_list:
writer.writerow([
store.get('cityName', ''),
store.get('storeName', ''),
store.get('addressDetail', '')
])
print(f"数据已保存到 {filename}")
方法二:保存为JSON文件 JSON格式能保留数据的原始结构,如果需要嵌套的、复杂的信息,JSON更合适。
import json
# ... 前面的请求和解析代码 ...
filename = 'kfc_beijing_page1.json'
with open(filename, 'w', encoding='utf-8') as f:
# indent参数让JSON文件有缩进,更易读
json.dump(result_dict, f, ensure_ascii=False, indent=2)
print(f"数据已保存到 {filename}")
4. 进阶技巧:实现全国多城市、多页数据抓取
只抓一个城市的一页数据,价值有限。真正的商业分析需要的是大规模数据。这就需要我们解决两个问题:翻页和多城市遍历。
4.1 自动翻页:抓取一个城市的所有门店
翻页的关键在于控制 pageIndex 这个参数。我们不知道北京总共有多少页,怎么办?一个稳健的策略是循环请求,直到服务器返回空数据为止。
import requests, json, time
def get_stores_by_city(city_name):
url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'
headers = {'User-Agent': '你的User-Agent字符串'}
all_stores = []
page_index = 1
while True:
print(f'正在抓取 {city_name} 第 {page_index} 页...')
data = {
'cname': '',
'pid': '',
'keyword': city_name,
'pageIndex': str(page_index),
'pageSize': '10',
}
try:
response = requests.post(url=url, data=data, headers=headers, timeout=10)
response.raise_for_status() # 检查请求是否成功
result = response.json()
stores_on_page = result.get('Table1', [])
if not stores_on_page: # 如果当前页没有数据,说明已经翻完了
print(f'{city_name} 的数据抓取完毕,共 {len(all_stores)} 条记录。')
break
all_stores.extend(stores_on_page)
page_index += 1
# 礼貌性延迟,避免请求过快给服务器带来压力
time.sleep(1)
except requests.exceptions.RequestException as e:
print(f'请求出错:{e}')
break
except json.JSONDecodeError:
print('响应内容不是有效的JSON格式')
break
return all_stores
# 使用函数
beijing_stores = get_stores_by_city('北京')
# 接下来可以将 beijing_stores 保存为文件
这个函数会一直请求,直到某一页返回的餐厅列表为空,然后自动停止。time.sleep(1) 这行代码很重要,它让每次请求间隔1秒,这是一个对目标网站友好的做法,也是我们作为数据采集者应有的素养。
4.2 多城市批量抓取与数据合并
有了单个城市的抓取函数,批量抓取全国城市就很简单了。我们只需要准备一个城市列表。
# 假设我们有一个中国主要城市的列表
city_list = ['北京', '上海', '广州', '深圳', '杭州', '成都', '武汉', '南京', '西安', '重庆']
all_city_stores = []
for city in city_list:
print(f'\n开始抓取城市:{city}')
stores = get_stores_by_city(city)
# 可以为每个城市单独保存一个文件
save_to_csv(stores, f'kfc_{city}.csv')
all_city_stores.extend(stores)
print(f'城市 {city} 抓取完成,累计总记录数:{len(all_city_stores)}')
# 城市间也增加一个稍长的延迟
time.sleep(2)
# 最后,将所有城市的数据合并保存到一个总文件中
save_to_csv(all_city_stores, 'kfc_all_cities.csv')
print('全国主要城市数据抓取全部完成!')
这里 save_to_csv 是一个你需要自己实现的函数,功能就是把店铺列表写入CSV文件。通过这样的循环,你就能构建起一个属于自己的、覆盖全国的肯德基门店数据库。
5. 避坑指南与伦理考量
爬虫看起来简单,但在实战中你会遇到各种各样的问题。这里分享几个我踩过的坑和必须注意的原则。
1. 请求被拒绝或返回奇怪数据?
- 检查请求头:有些网站会校验
User-Agent,甚至Referer(请求来源页)、Cookie。你需要把在开发者工具里看到的这些请求头信息,尽可能完整地复制到你的代码的headers字典里。 - 注意参数格式:有时候
pageIndex需要是整数而不是字符串,或者有其他隐藏参数。务必和浏览器发送的请求保持完全一致。可以尝试用requests的Session对象来保持会话状态。
2. 数据突然抓不到了?
- 网站更新了:这是最常见的原因。网站的接口地址、参数名称甚至数据加密方式都可能改变。你需要重新进行第一步的分析工作。
- IP被限制了:如果你在短时间内发送了大量请求,服务器可能会暂时封禁你的IP地址。解决方案是增加请求间隔(
time.sleep),或者对于更复杂的场景,使用IP代理池。但切记,对于肯德基官网这类公开查询,礼貌地、低速地抓取是首选。
3. 最重要的:遵守规则,善意爬取
- 查看
robots.txt:在网站根目录下(如https://www.kfc.com.cn/robots.txt),这个文件指明了网站允许和禁止爬虫访问的路径。尊重它。 - 控制请求频率:像我们代码里做的,在请求间加入延迟(例如1-3秒),避免对目标网站服务器造成冲击。你的目标是获取数据,而不是发起攻击。
- 明确数据用途:抓取到的公开数据,应用于个人学习、研究或合法的商业分析。绝对不要用于恶意骚扰、商业间谍、侵犯隐私或任何违法活动。也不要将大规模抓取的数据直接用于对外商业服务,这可能涉及版权和数据合规问题。
爬虫技术是一把锋利的刀,用好了能高效地获取信息,提升工作效率。但始终要对数据来源抱有敬畏之心,在技术能力提升的同时,培养起合规的数据使用意识。这才是能让你在这条路上走得更远的关键。
好了,从分析请求到写出可以稳定运行的爬虫脚本,整个流程我们已经走通了。你可以试着运行代码,先从你所在的城市开始,看看能抓到多少家肯德基。过程中遇到任何问题,不妨回头再看看分析步骤,或者检查一下参数是否完全匹配。编程和爬虫最有趣的部分,不就是这种不断发现问题、解决问题的过程吗?祝你抓取得愉快!
更多推荐


所有评论(0)