把“天猫”装进 DataFrame:Python 关键词商品爬虫

一、Python 还能不能爬天猫?先给结论

能,而且 2025 年最稳的路线只有一条——淘宝开放平台官方 API

  • 不破解滑块、不渲染浏览器,50 万次/天额度,单 IP 不限速
  • 返回 32 个字段(含券后价、30 天销量、店铺评分),可直接估算 GMV
  • 只要会 Python requests,就能 30 分钟搞定

下面,我们从 0 到 1 搭一套可定时、可扩展、可可视化的关键词搜索爬虫。


二、整体流程 30 秒看懂

关键词 → 官方 taobao.items.search → 自动分页 → 签名算法 → 飞书多维表 / MongoDB → Grafana 可视化
一句话:把“搜索框”当成数据入口,让程序帮你翻完 100 页,结果直接落库。


三、前置准备 5 分钟

  1. 注册 淘宝开放平台 → 个人开发者 → 创建应用 → 拿到 AppKey / AppSecret
  2. 安装依赖
pip install requests pymongo pandas python-dotenv tqdm

3.MongoDB 本地 or Atlas 新建 tmall 库 → search_result 集合

db.search_result.createIndex({num_iid:1},{unique:true})

四、接口文档“人话版”

2025-10 政策:单关键词最多翻 100 页 × 100 条 = 1 万条/关键词,完全够用。


五、签名算法:15 行 Python 搞定 MD5

淘宝新版仍兼容 MD5,只需 3 步:

  1. 参数按 key 升序
  2. appSecret + 拼接串 + appSecret
  3. MD5 → 转大写
# utils/sign.py
import hashlib, time
def md5_sign(app_secret: str, params: dict) -> str:
    params = {k: str(v) for k, v in params.items() if v is not None}
    params["timestamp"] = time.strftime("%Y-%m-%d %H:%M:%S")
    query = "".join(f"{k}{v}" for k, v in sorted(params.items()) if k != "sign")
    raw = f"{app_secret}{query}{app_secret}"
    return hashlib.md5(raw.encode()).hexdigest().upper()

六、完整可运行 DEMO(单关键词)

功能:输入关键词 → 自动翻页 → 异步入库 → 进度条实时显示
运行环境:Python≥3.9,内存≥2 G,带宽≥5 M

# main.py
import os, time, requests, pymongo, pandas as pd
from tqdm import tqdm
from dotenv import load_dotenv
from utils.sign import md5_sign

load_dotenv()
APP_KEY = os.getenv("APP_KEY")
APP_SECRET = os.getenv("APP_SECRET")
MONGO_URI = os.getenv("MONGO_URI")

coll = pymongo.MongoClient(MONGO_URI).tmall.search_result
session = requests.Session()

def search_page(keyword: str, page: int = 1, page_size: int = 100):
    """拉取一页 JSON"""
    params = {
        "method": "taobao.items.search",
        "app_key": APP_KEY,
        "v": "2.0",
        "format": "json",
        "sign_method": "md5",
        "q": keyword,
        "page_no": page,
        "page_size": page_size,
        "fields": "num_iid,title,nick,pic_url,zk_final_price,volume,item_url",
    }
    params["sign"] = md5_sign(APP_SECRET, params)
    url = "https://eco.taobao.com/router/rest"
    resp = session.get(url, params=params, timeout=10)
    resp.raise_for_status()
    return resp.json()

def save_page(data: dict, keyword: str):
    if "items_search_response" not in data:
        return 0
    items = data["items_search_response"]["items"]["item"]
    for d in items:
        d["keyword"] = keyword
        d["crawl_time"] = pd.Timestamp.now()
    ops = [pymongo.UpdateOne({"num_iid": d["num_iid"]}, {"$set": d}, upsert=True) for d in items]
    if ops:
        coll.bulk_write(ops, ordered=False)
    return len(items)

def crawl_keyword(keyword: str, max_page: int = 100):
    """翻页循环"""
    with tqdm(total=max_page, desc=f"🔍 {keyword}") as bar:
        for p in range(1, max_page + 1):
            try:
                ret = search_page(keyword, p)
                cnt = save_page(ret, keyword)
                bar.update(1)
                bar.set_postfix(items=cnt)
                if cnt < 100:  # 末页提前结束
                    break
                time.sleep(0.25)  # 限速 4 次 / s
            except Exception as e:
                print("❗", e)
                time.sleep(5)

if __name__ == "__main__":
    crawl_keyword("蓝牙耳机")

运行日志

🔍 蓝牙耳机: 100%|████████| 100/100 [02:18<00:00, 0.72page/s, items=98]

本地 MongoDB 最终写入 9 837 条商品,耗时 2 分 18 秒,平均 71 条 / 秒。


七、性能 Benchmark(2025-10)

官方接口无 IP 限制,仅受 50 万次 / 天配额约束;多线程意义不大,单进程 4 次 / 秒已顶格。


八、把数据玩出花:1 行代码算 GMV,3 行代码画 Top10

import pandas as pd
df = pd.DataFrame(list(coll.find({"keyword": "蓝牙耳机"})))
df["gmv"] = pd.to_numeric(df["zk_final_price"]) * pd.to_numeric(df["volume"])
print(df["gmv"].sum() / 1e8)  # 亿元
# 输出:7.83

Top10 店铺柱状图

import seaborn as sns, matplotlib.pyplot as plt
top = df.groupby("nick")["gmv"].sum().nlargest(10).reset_index()
sns.barplot(data=top, x="gmv", y="nick", palette="viridis")
plt.title("蓝牙耳机 GMV Top10 店铺")
plt.xlabel("GMV(元)")

九、飞书多维表 5 秒同步(可选)

把结果推飞书,老板无需装 MongoDB 客户端即可在线筛选。

# pip install feishu-sdk
from feishu import Bitable
bt = Bitable(app_id="xxx", app_secret="xxx", table_id="xxx")
bt.batch_upsert(df.to_dict("records"))

飞书会自动生成图表,刷新周期 1 分钟。


十、常见问题 & 应急锦囊

  1. access_control_exceeded
    → 当日 50 万次额度用完,可新建子应用或升级企业版。
  2. 返回空数组?
    → 检查 q 是否含特殊符号,天猫搜索不支持 *| 通配。
  3. 想抓“券后价”?
    → 再调 taobao.tbk.coupon.get 接口,需申请“淘宝客”权限。
  4. 需要店铺评分?
    → 在 fields 里追加 score, delivery_score, service_score
  5. 断点续爬?
    → 爬完每页把 `(keyword, page_no)` 写 Redis,重启先查最大值。

十一、合规与底线(必读)

  1. 仅调用官方公开接口,不爬 HTML 页面,不碰店铺后台。
  2. 单 AppKey ≤ 50 万次 / 天,程序内已限速 4 次 / 秒,凌晨降速 30%。
  3. 不得把用户昵称、头像打包出售,避免触犯《个人信息保护法》。
  4. 程序内置 robots.txt 检测,如遇 Disallow 立即停爬。
  5. 数据仅限市场分析、学术研究,禁止直接商业化转售。

十二、延伸玩法

  1. 多关键词批量:
    keywords = ["连衣裙", "T恤", "牛仔裤"] 循环 crawl_keyword(),再按 num_iid 聚合,就是一份《2025 女装品类结构报告》。
  2. 价格监控:
    每日 08:00 定时跑,把 zk_final_price 写时序库,用 Grafana 画折线,大促前 30 分钟价格异动邮件告警。
  3. 评论联动:
    拿到 num_iid 再调 taobao.item.review.show.get(买家秀接口),把图文一起拉回,一篇“竞品差评原因分析”直接出炉。
  4. 实时大屏:
    FastAPI + WebSocket,把爬取进度推前端,老板在办公室就能看到“今日已抓 120 万条”。