“超市”是一个非常宽泛的概念,它可能指:

- 大型连锁超市的官方网站:如沃尔玛、家乐福、永辉等,这些网站通常有反爬虫机制,需要更复杂的技术。
- 在线生鲜/超市平台:如盒马、叮咚买菜、美团买菜等,这些是 API 驱动的,爬取它们的 API 数据是最高效的方式。
- 某个具体的、规模较小的本地超市网站:这种网站可能结构简单,是学习
requests的绝佳入门案例。
下面,我将从最简单、最推荐的方式(爬取 API)开始,然后讲解如何爬取传统的网页,并最后提供一个完整的项目示例。
核心概念:requests 库
requests 是 Python 中最著名的 HTTP 库,它极大地简化了发送 HTTP 请求的过程,在爬虫中,我们用它来向服务器“请求”网页或数据。
主要功能:
requests.get(url): 发送 GET 请求,用于获取网页或数据。requests.post(url, data): 发送 POST 请求,常用于提交表单。response.status_code: 获取响应状态码,200表示成功。response.text: 获取响应的文本内容(HTML 或 JSON)。response.json(): 将响应内容直接解析为 Python 字典或列表(如果内容是 JSON 格式)。response.headers: 获取响应头信息。response.cookies: 获取响应的 cookies。
爬取在线超市的 API 数据 (推荐)
现代网站为了实现前后端分离,其数据通常通过 API 接口以 JSON 格式提供,这种方式比解析 HTML 简单得多,因为数据结构是固定的。

目标:获取某个商品列表页面的商品名称、价格和图片链接。
步骤:
-
找到 API 接口:
- 打开你想要爬取的超市网站(一个虚构的
supermarket-api.com)。 - 打开浏览器的“开发者工具”(通常按 F12 或右键 -> 检查)。
- 切换到 "Network" (网络) 标签页。
- 刷新页面或进行一些操作(如下拉加载更多商品)。
- 在网络请求列表中,寻找那些返回数据格式为
JSON的请求,它们的 URL 通常包含api,data,product等关键词,响应类型是application/json。
假设我们找到了这样一个 API:
(图片来源网络,侵删)- URL:
https://api.supermarket-api.com/v1/products?page=1&limit=20 - 请求方法:
GET - (JSON):
{ "status": "success", "data": { "products": [ { "id": 101, "name": "有机新鲜苹果", "price": 15.8, "unit": "500g", "image_url": "https://cdn.supermarket-api.com/imgs/apple.jpg" }, { "id": 102, "name": "纯牛奶", "price": 68.0, "unit": "1L*12盒", "image_url": "https://cdn.supermarket-api.com/imgs/milk.jpg" } // ... 更多商品 ] } }
- 打开你想要爬取的超市网站(一个虚构的
-
编写 Python 代码:
import requests import json # 用于美化打印 JSON,非必需 # 1. 定义 API 的 URL api_url = "https://api.supermarket-api.com/v1/products?page=1&limit=20" try: # 2. 发送 GET 请求 # headers 可以模拟浏览器访问,避免被简单识别为爬虫 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' } response = requests.get(api_url, headers=headers) # 3. 检查请求是否成功 # response.raise_for_status() 会在状态码不是 2xx 时抛出异常 response.raise_for_status() # 4. 解析 JSON 数据 # requests 库的 .json() 方法会自动将响应内容转为 Python 字典 data = response.json() # 5. 提取并打印我们想要的信息 if data.get("status") == "success": products = data["data"]["products"] print(f"成功获取到 {len(products)} 个商品信息:\n") for product in products: name = product.get("name") price = product.get("price") unit = product.get("unit") image_url = product.get("image_url") print(f"商品名称: {name}") print(f"价格: ¥{price} / {unit}") print(f"图片链接: {image_url}") print("-" * 30) except requests.exceptions.HTTPError as http_err: print(f"HTTP 错误发生: {http_err}") except requests.exceptions.RequestException as err: print(f"请求发生错误: {err}") except json.JSONDecodeError: print("响应内容不是有效的 JSON 格式")
优点:
- 数据结构清晰:JSON 对应 Python 字典,解析非常方便。
- 效率高:只传输数据,没有多余的 HTML 标签,流量小,速度快。
- 稳定:网站改版通常不会轻易改动其核心 API。
爬取传统网页的 HTML 内容
如果目标网站没有提供 API,或者你无法找到它,那么就需要解析返回的 HTML 页面,这通常需要另一个库 BeautifulSoup 或 lxml。
目标:获取一个超市网页上所有商品的名称和价格。
步骤:
-
分析网页结构:
- 在浏览器中打开目标商品页面。
- 右键点击一个商品名称 -> “检查”,找到包裹该名称的 HTML 标签和类名(class)或 ID。
- 同样,找到价格所在的标签和类名。
假设我们发现:
- 每个商品都在一个
<div class="product-item">容器里。 - 商品名称在
<h3 class="product-name">...</h3>中。 - 商品价格在
<span class="product-price">...</span>中。
-
编写 Python 代码:
import requests from bs4 import BeautifulSoup # 需要先安装: pip install beautifulsoup4 # 1. 定义目标网页的 URL html_url = "https://www.some-supermarket.com/products/fresh-fruit" try: # 2. 发送 GET 请求获取 HTML 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' } response = requests.get(html_url, headers=headers) response.raise_for_status() # 检查请求是否成功 # 3. 使用 BeautifulSoup 解析 HTML # 'html.parser' 是 Python 内置的解析器,也可以用 'lxml' (更快,需额外安装) soup = BeautifulSoup(response.text, 'html.parser') # 4. 使用 CSS 选择器查找所有商品 # .product-item 会查找所有 class 为 "product-item" 的标签 product_items = soup.find_all('div', class_='product-item') print(f"在页面上找到 {len(product_items)} 个商品:\n") # 5. 遍历每个商品,提取信息 for item in product_items: # 在每个商品容器内查找名称和价格 name_tag = item.find('h3', class_='product-name') price_tag = item.find('span', class_='product-price') # .get_text(strip=True) 可以获取标签内的文本并去除首尾空白 name = name_tag.get_text(strip=True) if name_tag else "未找到名称" price = price_tag.get_text(strip=True) if price_tag else "未找到价格" print(f"商品名称: {name}") print(f"商品价格: {price}") print("-" * 30) except requests.exceptions.RequestException as err: print(f"请求发生错误: {err}") except Exception as e: print(f"解析页面时发生错误: {e}")
注意:
- 这种方法非常脆弱,一旦网站更新了 HTML 结构(比如改了 class 名),你的爬虫就会立刻失效。
- 对于复杂的网站,JavaScript 动态加载的内容可能无法被
requests直接获取,这时需要更高级的工具如Selenium。
完整项目示例:爬取超市商品并保存为 CSV
让我们将场景一和场景二结合起来,做一个更实用的例子:爬取数据并保存到 CSV 文件,方便用 Excel 查看。
目标:爬取 API 数据,并将结果保存为 supermarket_products.csv 文件。
准备工作:
- 安装必要的库:
pip install requests beautifulsoup4 pandas
requests: 发送请求。beautifulsoup4: 虽然这个例子主要用requests.json(),但保留它以防万一需要解析 HTML。pandas: 处理数据并保存为 CSV 的神器。
代码 (supermarket_scraper.py):
import requests
import pandas as pd
import time
import random
# --- 配置 ---
# 假设的 API URL
BASE_API_URL = "https://api.supermarket-api.com/v1/products"
# 请求头,模拟浏览器
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',
'Accept': 'application/json, text/plain, */*'
}
# 要爬取的页数
PAGES_TO_SCRAPE = 5
# 输出文件名
OUTPUT_CSV_FILE = 'supermarket_products.csv'
def fetch_products_from_api(page):
"""从指定页面获取商品数据"""
params = {
'page': page,
'limit': 20 # 每页20个商品
}
try:
response = requests.get(BASE_API_URL, headers=HEADERS, params=params)
response.raise_for_status()
data = response.json()
if data.get("status") == "success":
return data["data"]["products"]
else:
print(f"第 {page} 页请求失败: {data.get('message')}")
return []
except requests.exceptions.RequestException as e:
print(f"请求第 {page} 页时出错: {e}")
return []
def main():
"""主函数"""
all_products = []
print(f"开始爬取,计划爬取 {PAGES_TO_SCRAPE} 页数据...")
for page in range(1, PAGES_TO_SCRAPE + 1):
print(f"正在爬取第 {page} 页...")
products_on_page = fetch_products_from_api(page)
if not products_on_page:
print(f"第 {page} 页没有获取到数据,可能已到达最后一页。")
break
all_products.extend(products_on_page)
# --- 礼貌性爬虫 ---
# 随机暂停 1 到 3 秒,避免请求过于频繁被封 IP
sleep_time = random.uniform(1, 3)
print(f"等待 {sleep_time:.2f} 秒...")
time.sleep(sleep_time)
if not all_products:
print("未能获取任何商品数据。")
return
print(f"\n爬取完成,共获取 {len(all_products)} 个商品。")
# --- 使用 pandas 处理数据 ---
# 将列表 of 字典 转换为 DataFrame
df = pd.DataFrame(all_products)
# 选择我们需要的列
# 假设 API 返回的字段是 'name', 'price', 'unit', 'image_url'
# 如果字段名不同,请根据实际情况修改
desired_columns = ['name', 'price', 'unit', 'image_url']
df = df[desired_columns]
# 保存为 CSV 文件
# index=False 表示不保存行索引 (0, 1, 2...)
# encoding='utf-8-sig' 可以确保用 Excel 打开时中文不会乱码
df.to_csv(OUTPUT_CSV_FILE, index=False, encoding='utf-8-sig')
print(f"数据已成功保存到文件: {OUTPUT_CSV_FILE}")
if __name__ == "__main__":
main()
重要注意事项与最佳实践
-
合法性:
- 永远不要爬取有版权声明或明确禁止爬取的网站。
- 查看网站的
robots.txt文件(https://www.example.com/robots.txt),它规定了哪些页面不希望被爬虫访问。 - 只爬取公开的、非私有的数据。
-
礼貌性爬虫:
- 设置
User-Agent:让你的请求看起来像来自普通浏览器。 - 控制请求频率:使用
time.sleep()在请求之间加入随机延迟,避免对服务器造成过大压力。 - 处理 cookies 和 session:如果需要登录才能访问,要妥善处理 cookies。
- 设置
-
反爬虫机制:
- IP 封禁:如果请求太频繁,你的 IP 可能会被暂时封禁,解决方案是使用代理 IP 池。
- 验证码:当检测到异常行为时,网站会弹出验证码,这通常需要使用第三方识别服务或更高级的自动化工具(如 Selenium)。
- 动态加载:数据由 JavaScript 生成,
requests无法获取,解决方案是使用Selenium或Playwright等工具模拟浏览器行为。
-
数据存储:
- 对于少量数据,CSV 文件足够。
- 对于大量数据,考虑使用数据库,如 SQLite (轻量级)、MySQL 或 PostgreSQL。
希望这份详细的指南能帮助你开始使用 Python requests 爬取超市数据!从爬取 API 开始是最佳实践,因为它更稳定、更高效。
