某猫商品数据爬虫:爬取品牌旗舰店数据,分析双11价格变化

简介: 本文揭秘双11“越促越贵”乱象,详解如何用Python爬虫稳定采集天猫商品价格数据:突破“星盾”反爬(动态令牌、IP画像、JS加密),集成站大爷隧道代理实现自动换IP,并通过定时采集+SQLite存储+可视化分析,还原真实价格曲线,助力消费者识破“先涨后降”套路。(239字)

引言

“同款冰箱今年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封禁问题,定时采集积累价格历史,数据分析揭示真实价格变化。

某猫的品牌旗舰店数据是洞察电商价格策略的窗口。通过合理的爬虫技术和数据分析方法,可以看清大促期间的价格真相——哪些是真优惠,哪些只是“数字游戏”。

最后提醒:数据采集行为应当遵循平台规则,控制请求频率。请遵守相关法律法规,仅将爬虫技术用于学习和研究目的。希望本文能帮助你在电商数据分析的道路上走得更远。

目录
相关文章
人工智能 缓存 前端开发
12026 63
人工智能 JavaScript 开发工具
4812 17
Web App开发 人工智能 API
1385 1
人工智能 Java BI
1472 1
开发工具 Swift git
1974 6
人工智能 JavaScript 测试技术
2406 2
人工智能 自然语言处理 安全
992 0
人工智能 JavaScript 测试技术
1200 4
缓存 JavaScript Shell
2102 3

热门文章

最新文章