引言
“同款冰箱今年618卖5723元,双11反而涨到7742元,这是促销还是抢钱?”河南张女士的遭遇并非个例。2025年双11期间,“越促越贵”的吐槽冲上热搜,黑猫投诉平台近2万条投诉直指电商平台“价格欺诈”。
在这个号称“史上最长”的双11(持续37天)里,消费者发现:刷新一下价格涨了,付完款优惠又来了,抄底几乎成了一场“玄学”。有人在多个账号测试同一商品,四个账号竟出现四个不同价格,最高价和最低价相差28元。
价格“瞬息万变”的背后,正是数据分析的价值所在。如果能持续爬取某猫品牌旗舰店的商品数据,记录价格随时间的变化曲线,就能看清双11期间的价格真相——哪些是真正的“低价”,哪些只是“先涨后降”的套路。
一、某猫反爬体系:2026年的“星盾”系统
某猫作为国内最大的B2C平台,其反爬体系已演进至第五代系统。想要稳定获取商品数据,必须先理解这套防御工事。
1.1 动态令牌与设备指纹
某猫的每个请求需携带包含时间戳、设备指纹、行为轨迹的动态令牌头部。Web端还会采集Canvas指纹、WebGL渲染器、字体列表等环境特征。
1.2 IP行为画像
基于请求间隔、URL访问序列、页面停留时间等维度建立机器学习模型,实时评估每个IP的可疑程度。单纯用同一个IP高频请求,几乎必被封。
1.3 动态渲染与价格加密
许多商品价格是在页面渲染后才动态加载的,基础HTTP请求只能拿到不完整的页面。更棘手的是,某猫还会通过JavaScript加密关键价格数据,直接抓HTML根本拿不到真实价格。
某猫的反爬是“全维度感知+实时风控”的系统,靠单一手段无法突破。
二、技术方案:如何稳定采集某猫商品数据
2.1 核心策略组合拳
应对某猫的反爬,需要“组合拳”:
(1)隧道代理(核心):某猫会基于IP进行行为画像和封禁。隧道代理实现每次请求自动切换出口IP,让反爬系统无法摸透你的访问模式。
(2)请求头伪装:完整的User-Agent、Referer、Accept-Language等,模拟真实浏览器。
(3)Cookie与会话管理:某猫的Cookie默认有效期7-15天,需要维护Cookie池。
(4)随机延迟:两次请求间隔需随机,避免固定频率被识别。
2.2 站大爷隧道代理集成
站大爷隧道代理的入口格式为 http://用户名:密码@tps.zdaye.com:8080。核心优势在于:
- 自动切换IP:无需手动维护代理池,每次请求自动更换出口IP
- 覆盖全国99%地域:支持300+城市IP精准定位
- 灵活周期控制:通过
period参数自定义IP更换频率
在requests中集成:
import requests
from fake_useragent import UserAgent
# 站大爷隧道代理配置
PROXY_CONFIG = {
"http": "http://用户名:密码@tps.zdaye.com:8080",
"https": "http://用户名:密码@tps.zdaye.com:8080"
}
ua = UserAgent()
def fetch_tmall_page(url, retry=3):
headers = {
"User-Agent": ua.random,
"Referer": "https://www.tmall.com/",
"Accept": "text/html,application/xhtml+xml",
"Accept-Language": "zh-CN,zh;q=0.9"
}
for attempt in range(retry):
try:
resp = requests.get(url, headers=headers, proxies=PROXY_CONFIG, timeout=15)
if resp.status_code == 200:
return resp.text
if resp.status_code in [403, 429]:
print(f"第{attempt+1}次请求被拒绝,隧道代理自动切换IP重试...")
time.sleep(3 * (attempt + 1))
except Exception as e:
print(f"请求异常: {e}")
time.sleep(3)
return None
如需精细控制IP更换周期(比如30秒换一次),可使用period参数:
PROXY_CONFIG = {
"http": "http://用户名-period-30:密码@tps.zdaye.com:8080",
"https": "http://用户名-period-30:密码@tps.zdaye.com:8080"
}
三、爬虫实战:爬取品牌旗舰店商品数据
3.1 数据采集目标
针对某猫品牌旗舰店,采集以下数据:
| 字段 | 说明 | 分析价值 |
| 商品标题 | 完整名称 | 品牌识别、分类 |
| 当前价格/促销价 | 实时售价 | 价格曲线基础 |
| 月销量 | 近30天销量 | 商品热度 |
| 评价数 | 累计评价 | 口碑参考 |
| 采集时间 | 数据快照时间 | 时序分析 |
3.2 完整爬虫实现
import requests
from bs4 import BeautifulSoup
import time
import random
import json
import pandas as pd
from fake_useragent import UserAgent
from datetime import datetime
import sqlite3
class TmallScraper:
def __init__(self, use_tunnel=True):
self.session = requests.Session()
self.ua = UserAgent()
self.use_tunnel = use_tunnel
if use_tunnel:
self.proxies = {
"http": "http://用户名:密码@tps.zdaye.com:8080",
"https": "http://用户名:密码@tps.zdaye.com:8080"
}
else:
self.proxies = None
# 初始化数据库
self._init_db()
def _init_db(self):
"""初始化SQLite数据库存储价格历史"""
self.conn = sqlite3.connect('tmall_prices.db')
cursor = self.conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS price_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
product_id TEXT,
product_name TEXT,
brand TEXT,
price REAL,
sales INTEGER,
collect_time TEXT
)
''')
self.conn.commit()
def _get_headers(self):
return {
"User-Agent": self.ua.random,
"Referer": "https://www.tmall.com/",
"Accept": "text/html,application/xhtml+xml",
"Accept-Language": "zh-CN,zh;q=0.9",
"Connection": "keep-alive"
}
def search_brand_products(self, brand_name, max_pages=5):
"""
搜索某猫品牌旗舰店的商品
"""
results = []
for page in range(1, max_pages + 1):
url = f"https://list.tmall.com/search_shopitem.htm?q={brand_name}&pageNo={page}"
print(f"搜索品牌 {brand_name} 第{page}页...")
html = self._fetch(url)
if not html:
break
soup = BeautifulSoup(html, 'html.parser')
items = soup.find_all('div', class_='product-item') # 实际选择器需确认
for item in items:
try:
title = item.find('a', class_='product-title').text.strip()
price = item.find('span', class_='price').text.strip()
sales = item.find('span', class_='sales').text.strip()
link = item.find('a').get('href', '')
results.append({
'brand': brand_name,
'title': title,
'price': float(price.replace('¥', '').replace(',', '')),
'sales': int(sales.replace('人付款', '').replace('+', '')),
'link': link,
'collect_time': datetime.now().isoformat()
})
except Exception as e:
continue
time.sleep(random.uniform(2, 4))
return results
def save_to_db(self, products):
"""保存价格快照到数据库"""
cursor = self.conn.cursor()
for p in products:
cursor.execute('''
INSERT INTO price_history
(product_id, product_name, brand, price, sales, collect_time)
VALUES (?, ?, ?, ?, ?, ?)
''', (p.get('link', ''), p.get('title', ''), p.get('brand', ''),
p.get('price', 0), p.get('sales', 0), p.get('collect_time', '')))
self.conn.commit()
print(f"已保存 {len(products)} 条价格记录")
def close(self):
self.conn.close()
# 使用示例
if __name__ == "__main__":
scraper = TmallScraper(use_tunnel=True)
# 监控多个品牌
brands = ["Apple", "华为", "小米", "美的"]
all_data = []
for brand in brands:
print(f"\n开始采集品牌: {brand}")
products = scraper.search_brand_products(brand, max_pages=3)
scraper.save_to_db(products)
all_data.extend(products)
time.sleep(random.uniform(3, 5))
scraper.close()
print(f"采集完成,共 {len(all_data)} 条商品记录")
3.3 定时采集与价格趋势分析
实际的价格监控需要定时运行(如每天10:00和20:00各一次),积累历史数据后分析趋势。
import schedule
def daily_price_task():
scraper = TmallScraper(use_tunnel=True)
brands = ["Apple", "华为", "小米", "美的"]
for brand in brands:
products = scraper.search_brand_products(brand, max_pages=2)
scraper.save_to_db(products)
scraper.close()
# 每天10:00和20:00执行
schedule.every().day.at("10:00").do(daily_price_task)
schedule.every().day.at("20:00").do(daily_price_task)
while True:
schedule.run_pending()
time.sleep(60)
四、双11价格真相:数据能告诉我们什么?
持续采集的价格数据可以揭示双11期间的价格变化规律。
4.1 价格曲线分析
import sqlite3
import pandas as pd
import matplotlib.pyplot as plt
conn = sqlite3.connect('tmall_prices.db')
# 查询特定商品的价格历史
df = pd.read_sql_query('''
SELECT product_name, price, collect_time
FROM price_history
WHERE product_name LIKE '%iPhone%'
ORDER BY collect_time
''', conn)
# 绘制价格趋势图
df['collect_time'] = pd.to_datetime(df['collect_time'])
plt.figure(figsize=(12, 6))
for name, group in df.groupby('product_name'):
plt.plot(group['collect_time'], group['price'], marker='o', label=name)
plt.title('双11期间iPhone价格变化趋势')
plt.xlabel('时间')
plt.ylabel('价格 (元)')
plt.legend()
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig('price_trend.png')
conn.close()
4.2 双11价格真相
根据2025年双11的调查数据,消费者遭遇的典型问题包括:
价格倒挂:同款冰箱618卖5723元,双11反而涨到7742元,价差高达2019元。
凑单反贵:单独购买1298.72元的羽绒服,凑单后反而变成1302.11元。原因是优惠券有总额度上限,分摊到多件商品后单件优惠减少。
VIP差异定价:同样开通88VIP的不同账号,同一商品结算价相差17元。
这些现象说明:双11的“低价”并不总是真的低价。只有通过持续的数据采集和价格追踪,才能看清真实的价格变化曲线。
五、常见问题与避坑指南
5.1 请求被拦截怎么办?
- 检查是否携带了完整的请求头
- 确认Cookie是否有效
- 使用隧道代理自动切换IP
- 增加请求间隔到3-5秒
5.2 价格数据获取不全怎么办?
- 优先采集移动端接口(m.tmall.com),加密相对简单
- 使用Selenium/Playwright渲染动态价格
- 关注价格接口的API调用,而非页面解析
5.3 IP频繁被封怎么办?
- 使用站大爷隧道代理的
period参数控制IP更换周期 - 避免固定时间间隔请求,加入随机延迟
- 配合Cookie池轮换使用
5.4 法律与合规提醒
- 爬取前查看某猫的
robots.txt - 控制请求频率,避免对服务器造成过大压力
- 仅将数据用于学习和个人研究目的
六、总结
双11的“低价狂欢”背后,藏着复杂的定价策略和优惠规则。用数据揭穿“先涨后降”的套路,正是爬虫技术在消费者权益保护中的价值。
本文的核心方案可以概括为:
| 挑战 | 解决方案 |
| 动态令牌与设备指纹 | 完整请求头 + User-Agent轮换 |
| IP行为画像 | 站大爷隧道代理,自动切换IP |
| 动态渲染价格 | 定时采集 + 数据库存储历史 |
| 价格真相揭示 | 价格曲线可视化 + 多品牌对比 |
技术选型速览:推荐“
requests+BeautifulSoup+ 站大爷隧道代理”的组合方案。隧道代理解决IP封禁问题,定时采集积累价格历史,数据分析揭示真实价格变化。
某猫的品牌旗舰店数据是洞察电商价格策略的窗口。通过合理的爬虫技术和数据分析方法,可以看清大促期间的价格真相——哪些是真优惠,哪些只是“数字游戏”。
最后提醒:数据采集行为应当遵循平台规则,控制请求频率。请遵守相关法律法规,仅将爬虫技术用于学习和研究目的。希望本文能帮助你在电商数据分析的道路上走得更远。