×

蘑菇街 item_get 接口对接全攻略:从入门到精通

万邦科技Lex 万邦科技Lex 发表于2025-10-28 11:18:59 浏览149 评论0

抢沙发发表评论

       注册账号免费测试蘑菇街API数据接口

蘑菇街是国内知名的时尚电商平台,聚焦年轻女性用户,以服饰、美妆、家居等品类为核心,其商品详情数据(如售价、规格、库存、店铺信息等)是电商卖家选品、比价工具开发、市场分析的重要依据。由于蘑菇街官方 API 接入门槛较高(需企业资质且功能有限),开发者常通过页面解析或第三方服务实现商品详情(item_get)的获取。本文将系统讲解接口对接逻辑、技术实现、反爬应对及最佳实践,帮助开发者构建稳定的商品详情获取系统。

一、接口基础认知(核心功能与场景)

  1. 核心功能蘑菇街item_get接口(非官方命名,泛指通过商品 ID 获取详情的工具)通过商品 ID(item_id)获取目标商品的全量信息,核心字段包括:
    • 基础信息:商品 ID、标题、主图(多图)、类目、详情页 URL、上架时间、是否预售

    • 价格信息:原价(original_price)、现价(current_price)、折扣(如 “8 折”)、优惠券信息

    • 规格信息:颜色、尺码(如 “XS/S/M”)、对应库存与价格(部分商品规格不同价)

    • 店铺信息:店铺 ID、名称、评分(如 “4.8 分”)、粉丝数、主营类目、是否旗舰店

    • 交易数据:月销量(如 “月销 2000+”)、评价数、好评率(如 “98% 好评”)

    • 详情描述:商品详情图文(HTML)、售后服务(如 “7 天无理由”)、物流信息

  2. 典型应用场景
    • 电商卖家选品:获取热门服饰的价格、销量、评价,判断市场潜力

    • 比价工具开发:整合蘑菇街与淘宝、京东等平台数据,为用户提供价格对比

    • 市场趋势分析:跟踪 “连衣裙”“口红” 等类目商品的价格波动、款式变化

    • 店铺监控:监控竞品店铺的新品上架、促销活动及库存变化

  3. 接口特性
    • 半官方性:蘑菇街有开放平台(open.mogujie.com),但个人开发者难接入,更多依赖页面解析

    • C 端属性:数据偏向消费者视角(如折扣、优惠券、评价),与批发平台差异显著

    • 反爬严格:包含 IP 限制、User-Agent 校验、Cookie 验证、JS 加密参数(如_m_h5_tk

    • 动态加载:大部分数据(价格、库存、销量)通过 AJAX 接口加载,依赖前端 JS 渲染

二、对接前置准备(环境与工具)

  1. 开发环境
    • 网络请求:requests(同步请求)、aiohttp(异步批量获取)

    • 页面解析:BeautifulSoup(HTML 解析)、lxml(XPath 提取)

    • 反爬工具:fake_useragent(随机 User-Agent)、execjs(执行 JS 生成加密参数)

    • 动态渲染:selenium(应对 JS 加密严重的场景,低频使用)

    • 开发语言:Python(推荐,生态丰富,适合处理动态数据与反爬)

    • 核心库:

  2. 商品 ID 与 URL 结构蘑菇街商品详情页 URL 格式主要有两种(PC 端与移动端):
    • PC 端:https://item.mogujie.com/detail/{item_id}.htm

    • 移动端(H5):https://m.mogujie.com/detail/{item_id}?from=pc

      其中item_id为商品唯一标识(纯数字,如12345678)。

      示例:某连衣裙详情页 https://item.mogujie.com/detail/12345678.htm,商品 ID 为12345678

  3. 页面结构分析(关键步骤)通过浏览器开发者工具(F12)分析详情页,核心数据分布:
    • 静态数据:标题、主图等基础信息在 HTML 中,但大部分通过script标签内的 JSON 数据(如window.__INITIAL_STATE__)存储;

    • 动态数据:价格、库存、销量等通过 AJAX 接口加载,需携带加密参数(如_m_h5_tk_m_h5_tk_enc),接口格式通常为https://gateway.mogujie.com/{api_path}?{params}

  4. 加密参数解析(核心难点)蘑菇街动态接口依赖_m_h5_tk参数(基于 Cookie 中的_m_h5_tk与时间戳、路径生成),生成逻辑如下:
    • 从 Cookie 中获取_m_h5_tk的前缀(token_m_h5_tk格式为token_xxxx);

    • 拼接token + "&" + timestamp + "&" + appKey + "&" + dataappKey通常为12574478);

    • 通过 MD5 加密生成签名,最终参数为_m_h5_tk=token_签名&_m_h5_tk_enc=xxx

三、接口调用流程(基于动态解析)

以 “获取某连衣裙商品详情” 为例,核心流程为参数准备加密参数生成动态接口请求数据解析结构化处理
  1. 动态接口定位关键动态接口示例(需替换item_id):
    • 商品基础信息:https://gateway.mogujie.com/api/item/detail?itemId={item_id}

    • 价格与库存:https://gateway.mogujie.com/api/item/price?itemId={item_id}

    • 销量与评价:https://gateway.mogujie.com/api/item/rate?itemId={item_id}

      这些接口均需携带_m_h5_tk_m_h5_tk_enctimestamp等参数。

  2. 请求头与加密参数构建
    • 请求头需包含User-Agent(移动端优先,反爬较松)、RefererCookie

      python
      运行
      headers = {
          "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148",
          "Referer": "https://m.mogujie.com/",
          "Cookie": "_m_h5_tk=xxx; _m_h5_tk_enc=xxx; ..."  # 从浏览器获取}
    • 加密参数生成(需通过 JS 执行生成签名):

      python
      运行
      import execjsimport timeimport hashlibdef generate_m_h5_tk(cookie_tk, data, app_key="12574478"):
          token = cookie_tk.split("_")[0]  # 提取token前缀
          timestamp = str(int(time.time() * 1000))
          # 拼接签名源串
          sign_str = f"{token}&{timestamp}&{app_key}&{data}"
          sign = hashlib.md5(sign_str.encode()).hexdigest()
          return f"{token}_{sign}", timestamp# 使用示例cookie_tk = "xxx"  # 从Cookie的_m_h5_tk中提取data = '{"itemId":"12345678"}'  # 接口请求数据m_h5_tk, timestamp = generate_m_h5_tk(cookie_tk, data)
  3. 数据解析与整合从动态接口响应中提取核心字段,示例响应解析:
    • 商品基础信息接口返回:

      json
      {
        "data": {
          "item": {
            "itemId": "12345678",
            "title": "夏季碎花连衣裙",
            "mainImg": "https://img.mogujie.com/xxx.jpg",
            "imgs": ["https://img.mogujie.com/xxx1.jpg", ...],
            "shopId": "87654",
            "shopName": "时尚女装店"
          }
        }}
    • 价格接口返回:

      json
      {
        "data": {
          "price": {
            "originalPrice": 199,
            "currentPrice": 159,
            "discount": "8折"
          },
          "stock": 500
        }}
  4. 数据结构化合并多接口数据,形成标准化字典:
    python
    运行
    standardized_data = {
        "item_id": item_id,
        "title": title,
        "price": {
            "original": original_price,
            "current": current_price,
            "discount": discount    },
        "stock": total_stock,
        "sales": monthly_sales,  # 月销量
        "specs": specs_list,  # 颜色+尺码+库存列表
        "shop": {
            "id": shop_id,
            "name": shop_name,
            "score": shop_score    },
        "images": img_list,
        "update_time": time.strftime("%Y-%m-%d %H:%M:%S")}

四、代码实现示例(Python)

以下是item_get接口的完整实现,包含加密参数生成、动态接口调用、数据解析及反爬处理:
import requests
import time
import random
import re
import hashlib
import json
from fake_useragent import UserAgent
from typing import Dict, List

class MogujieItemApi:
    def __init__(self, cookie: str, proxy_pool: List[str] = None):
        self.base_api = "https://gateway.mogujie.com"
        self.app_key = "12574478"  # 固定appKey
        self.cookie = cookie
        self.cookie_tk = self._extract_cookie_tk()  # 从Cookie中提取_m_h5_tk
        self.ua = UserAgent()
        self.proxy_pool = proxy_pool

    def _extract_cookie_tk(self) -> str:
        """从Cookie中提取_m_h5_tk"""
        for cookie in self.cookie.split(";"):
            if "_m_h5_tk" in cookie:
                return cookie.split("=")[1].strip()
        raise ValueError("Cookie中未找到_m_h5_tk,请检查Cookie是否有效")

    def _generate_sign(self, data: str) -> tuple:
        """生成加密参数_m_h5_tk和timestamp"""
        token = self.cookie_tk.split("_")[0]
        timestamp = str(int(time.time() * 1000))
        # 拼接签名源串
        sign_str = f"{token}&{timestamp}&{self.app_key}&{data}"
        sign = hashlib.md5(sign_str.encode()).hexdigest()
        m_h5_tk = f"{token}_{sign}"
        return m_h5_tk, timestamp

    def _get_headers(self) -> Dict[str, str]:
        """生成请求头"""
        return {
            "User-Agent": self.ua.mobile,  # 优先使用移动端UA,反爬较松
            "Referer": "https://m.mogujie.com/",
            "Origin": "https://m.mogujie.com",
            "Cookie": self.cookie,
            "Content-Type": "application/json"
        }

    def _get_proxy(self) -> Dict[str, str]:
        """随机获取代理"""
        if self.proxy_pool and len(self.proxy_pool) > 0:
            proxy = random.choice(self.proxy_pool)
            return {"http": proxy, "https": proxy}
        return None

    def _fetch_api(self, api_path: str, data: Dict) -> Dict:
        """调用蘑菇街动态API"""
        try:
            # 生成加密参数
            data_str = json.dumps(data, ensure_ascii=False)
            m_h5_tk, timestamp = self._generate_sign(data_str)
            # 构建URL参数
            params = {
                "_m_h5_tk": m_h5_tk,
                "_m_h5_tk_enc": "",  # 部分接口无需enc,复杂接口需额外处理
                "timestamp": timestamp,
                "appKey": self.app_key
            }
            url = f"{self.base_api}{api_path}"
            headers = self._get_headers()
            proxy = self._get_proxy()

            # 发送请求(带随机延迟)
            time.sleep(random.uniform(1, 3))
            response = requests.post(
                url=url,
                params=params,
                data=data_str,
                headers=headers,
                proxies=proxy,
                timeout=10
            )
            response.raise_for_status()
            return response.json()
        except Exception as e:
            print(f"API请求失败: {str(e)}")
            return {}

    def _parse_base_info(self, base_data: Dict) -> Dict:
        """解析基础信息接口数据"""
        item = base_data.get("data", {}).get("item", {})
        return {
            "title": item.get("title", ""),
            "main_image": item.get("mainImg", ""),
            "images": item.get("imgs", []),
            "shop": {
                "id": item.get("shopId", ""),
                "name": item.get("shopName", ""),
                "score": item.get("shopScore", 0)
            }
        }

    def _parse_price_stock(self, price_data: Dict) -> Dict:
        """解析价格与库存接口数据"""
        price_info = price_data.get("data", {}).get("price", {})
        return {
            "price": {
                "original": price_info.get("originalPrice", 0),
                "current": price_info.get("currentPrice", 0),
                "discount": price_info.get("discount", "")
            },
            "total_stock": price_data.get("data", {}).get("stock", 0),
            "specs": price_data.get("data", {}).get("specs", [])  # 规格+库存
        }

    def _parse_sales(self, sales_data: Dict) -> Dict:
        """解析销量与评价接口数据"""
        sales_info = sales_data.get("data", {})
        return {
            "monthly_sales": sales_info.get("monthlySales", 0),
            "comment_count": sales_info.get("commentCount", 0),
            "good_rate": sales_info.get("goodRate", 0)  # 好评率(如98表示98%)
        }

    def item_get(self, item_id: str) -> Dict:
        """
        获取蘑菇街商品详情
        :param item_id: 商品ID(如12345678)
        :return: 标准化商品数据
        """
        try:
            # 1. 获取基础信息
            base_data = self._fetch_api(
                api_path="/api/item/detail",
                data={"itemId": item_id}
            )
            if not base_data.get("success"):
                return {"success": False, "error_msg": "基础信息接口返回失败"}
            base_info = self._parse_base_info(base_data)

            # 2. 获取价格与库存
            price_data = self._fetch_api(
                api_path="/api/item/price",
                data={"itemId": item_id}
            )
            price_stock = self._parse_price_stock(price_data)

            # 3. 获取销量与评价
            sales_data = self._fetch_api(
                api_path="/api/item/rate",
                data={"itemId": item_id, "page": 1, "size": 1}
            )
            sales_info = self._parse_sales(sales_data)

            # 4. 合并数据
            result = {
                "success": True,
                "data": {
                    "item_id": item_id,** base_info,
                    **price_stock,** sales_info,
                    "update_time": time.strftime("%Y-%m-%d %H:%M:%S")
                }
            }
            return result

        except Exception as e:
            return {"success": False, "error_msg": f"获取失败: {str(e)}", "code": -1}

# 使用示例
if __name__ == "__main__":
    # 从浏览器获取的Cookie(需包含_m_h5_tk)
    COOKIE = "_m_h5_tk=xxx; _m_h5_tk_enc=xxx; ..."  # 替换为实际Cookie
    # 代理池(替换为有效代理)
    PROXIES = [
        "http://123.45.67.89:8888",
        "http://98.76.54.32:8080"
    ]

    # 初始化API客户端
    api = MogujieItemApi(cookie=COOKIE, proxy_pool=PROXIES)

    # 获取商品详情(示例item_id)
    item_id = "12345678"  # 替换为实际商品ID
    result = api.item_get(item_id)

    if result["success"]:
        data = result["data"]
        print(f"商品标题: {data['title']}")
        print(f"价格: 原价{data['price']['original']}元 | 现价{data['price']['current']}元 | {data['price']['discount']}")
        print(f"销量: 月销{data['monthly_sales']}件 | 评价{data['comment_count']}条 | 好评率{data['good_rate']}%")
        print(f"库存: {data['total_stock']}件 | 店铺: {data['shop']['name']}(评分{data['shop']['score']})")
        print(f"主图: {data['main_image']}")
        print("\n规格信息(前3条):")
        for spec in data["specs"][:3]:
            print(f"  {spec.get('color')} | {spec.get('size')} | 库存: {spec.get('stock')}件 | 价格: {spec.get('price')}元")
    else:
        print(f"获取失败: {result['error_msg']}(错误码: {result.get('code')})")

五、关键技术难点与解决方案

  1. 加密参数_m_h5_tk生成
    • 从浏览器 Cookie 中提取_m_h5_tk,解析出token前缀;

    • token&timestamp&appKey&data格式拼接字符串,通过 MD5 加密生成签名;

    • 当参数失效(返回-1001错误)时,自动重新获取 Cookie 并更新_m_h5_tk(可通过 Selenium 自动登录刷新 Cookie)。

    • 问题:蘑菇街动态接口依赖_m_h5_tk参数,其生成逻辑涉及 Cookie 解析、MD5 加密,且定期失效(通常 2 小时)。

    • 解决方案

  2. 动态接口碎片化
    • 梳理核心接口依赖关系,按 “基础信息→价格库存→销量评价” 顺序请求;

    • 封装_fetch_api通用方法,统一处理参数生成与请求异常;

    • 对接口响应进行空值判断,避免单接口失败导致整体崩溃。

    • 问题:商品数据分散在多个接口(基础信息、价格、库存、销量等),需多次请求并整合。

    • 解决方案

  3. 反爬机制对抗
    • 代理 IP 轮换:使用高匿代理池,每 3-5 次请求切换 IP,避免单一 IP 被标记;

    • 请求频率控制:单 IP 每分钟请求≤5 次,两次请求间隔 1-3 秒(随机波动);

    • Cookie 池维护:通过多个账号获取 Cookie,定期(1 小时)刷新,避免_m_h5_tk失效;

    • 验证码处理:若触发验证码,暂停当前代理并切换 Cookie,使用 Selenium 手动验证(适合低频场景)。

    • 问题:蘑菇街反爬严格,高频请求会触发 IP 封锁(403)、参数失效或验证码。

    • 解决方案

  4. 移动端与 PC 端选择
    • 优先使用移动端接口(m.mogujie.com域名),降低反爬压力;

    • 若需完整数据(如详情页 HTML),可结合 PC 端静态页面解析,补充移动端接口缺失字段。

    • 问题:PC 端接口反爬更严格(如额外 JS 加密),移动端 H5 接口相对宽松但数据字段较少。

    • 解决方案

六、最佳实践与合规要点

  1. 系统架构设计采用 “加密参数管理 + 分布式采集” 架构,适配蘑菇街严格反爬:
    • 参数管理层:集中生成与缓存_m_h5_tk,定期(30 分钟)更新,避免重复计算;

    • 采集层:多节点并行采集,每个节点绑定独立 Cookie 与代理池,节点间请求间隔≥5 秒;

    • 存储层:用 Redis 缓存热门商品(15 分钟过期,蘑菇街价格变动较快),MySQL 存储历史数据;

    • 监控层:实时监控接口响应码(重点跟踪-1001参数失效)、代理存活率,异常时自动切换资源。

  2. 性能优化策略
    • 批量异步请求:使用aiohttp并发处理多个item_id(控制并发数≤3),共享 Cookie 与代理;

    • 按需请求:非核心字段(如详情页 HTML)可选择性获取,优先保证价格、库存、销量等关键数据;

    • 失败重试机制:对-1001(参数失效)、403(反爬)等错误,自动重试 2 次(更换代理 / Cookie 后)。

  3. 合规性与风险控制
    • 遵守平台规则:蘑菇街开放平台禁止未授权爬取,商业使用需申请官方 API;

    • 频率限制:单 IP 日请求量≤500 次,避免对服务器造成压力;

    • 数据用途:不得将数据用于恶意竞争、虚假宣传,需注明来源 “蘑菇街”。

  4. 反爬适应性调整
    • 定期(每周)检查接口参数变化(如appKey更新),更新加密逻辑;

    • 当反爬升级(如新增sign参数),通过逆向最新 JS 代码(使用charles抓包 +jsbeautifier格式化)提取新规则;

    • 建立接口降级策略:动态接口失败时, fallback 到静态页面解析(适合数据精度要求不高的场景)。

七、总结

蘑菇街item_get接口的对接核心在于加密参数_m_h5_tk的正确生成多接口数据的整合严格的反爬对抗策略。开发者需重点关注:
  1. 动态接口的定位与参数加密逻辑(尤其是_m_h5_tk的生成);

  2. 移动端与 PC 端接口的选择(平衡反爬压力与数据完整性);

  3. 代理池、Cookie 池的精细化管理(应对高频请求与参数失效)。

通过本文的技术方案,可构建稳定的商品详情获取系统,为电商选品、市场分析等场景提供数据支持。实际应用中,需优先考虑官方 API 接入,合规使用数据,避免法律风险。


群贤毕至

访客