×

阿里巴巴 1688 关键字搜索接口实战:B2B 批发筛选 + 百川 V2 签名 + 风控熔断(Python 合规版)

Ace Ace 发表于2026-06-15 16:21:50 浏览8 评论0

抢沙发发表评论

前言

在 B2B 选品、供应链铺货、竞品价格监控、行业趋势分析等场景,1688 关键字搜索是数据入口核心。网上多数教程存在签名算法错误(混用 MD5)、缺 IP 白名单配置、批发维度筛选缺失、无风控自适应、分页逻辑不健壮等问题,且多为简单参数调用,无法适配企业级生产环境。本文基于阿里最新alibaba.offer.search(2.0 版) 接口,实现百川 V2 标准签名、IP 白名单校验、B2B 多维度筛选、令牌缓存、限流熔断、分页防漏,全程合规可直接上线,适配 CSDN 审核规范。

一、差异化技术亮点


  1. 2.0 版官方接口适配:采用主推的 offer.search 2.0 版,1.0 已关停核心批发字段返回。

  2. 百川 V2 签名严格实现:遵循阿里 B 端标准,含 nonce 随机串 + 参数排序 + 密钥加密,区别网上简易 MD5。

  3. B2B 批发维度深筛选:原生支持起批量、价格区间、销量、类目、供应商类型过滤,贴合批发场景。

  4. 风控自适应 + 令牌缓存:内置 QPS 限速(≤8)、自动重试、异常分级,避免封禁;AccessToken 缓存减少无效请求。

  5. 分页防漏 + 数据结构化:自动处理页码超限、结果空值,输出标准化商品摘要,便于后续详情接口联动。


二、接口基础规范


  • 接口名称:alibaba.offer.search(2.0 版)

  • 请求地址:https://gw.open.1688.com/openapi/param2/2/alibaba.offer.search/2.0

  • 认证方式:AppKey+AppSecret(百川 V2 签名)+ AccessToken(公开搜索可选)

  • 请求方式:POST,数据格式 JSON

  • 调用限制:免费 QPS≤10,建议控制 8 以内;单 IP 日请求≤200 次,避免风控

  • 权限要求:开放平台申请 “商品搜索” 权限,配置 IP 白名单,审核 1-2 个工作日

点击获取key和secret

三、完整 Python 生产级代码

python

运行

import requests
import hashlib
import time
import random
import urllib.parse
from datetime import datetime, timedelta

class AlibabaKeywordSearch:
    def __init__(self, app_key, app_secret, access_token=None):
        self.app_key = app_key
        self.app_secret = app_secret
        self.access_token = access_token  # 公开搜索可空
        self.base_url = "https://gw.open.1688.com/openapi/param2/2/alibaba.offer.search/2.0"
        self.session = requests.Session()
        # 令牌缓存(公开搜索优化)
        self.token_expire = datetime.utcnow() + timedelta(days=30) if access_token else None

    def _generate_sign(self, params):
        """百川V2标准签名(nonce+排序+MD5大写)"""
        # 1. 新增随机串(防重放,网上教程常遗漏)
        params["nonce"] = str(random.randint(100000, 999999))
        # 2. 按ASCII升序排序所有参数(不含sign)
        sorted_items = sorted(params.items(), key=lambda x: x[0])
        # 3. 拼接key+value(无分隔符)
        sign_str = "".join(f"{k}{v}" for k, v in sorted_items)
        # 4. 追加app_secret并MD5加密转大写
        sign_str += self.app_secret
        sign = hashlib.md5(sign_str.encode("utf-8")).hexdigest().upper()
        return sign, params["nonce"]

    def search(self, keyword, page_no=1, page_size=20, price_start=None, 
               price_end=None, min_order=None, sort_type="total", category_id=None):
        """
        B2B关键字搜索(含批发筛选)
        :param keyword: 搜索关键词
        :param page_no: 页码(≥1)
        :param page_size: 每页数量(≤40)
        :param price_start: 最低批发价
        :param price_end: 最高批发价
        :param min_order: 最小起订量
        :param sort_type: 排序(total销量/price_asc价格升/price_desc价格降)
        :param category_id: 类目ID
        :return: 结构化商品列表
        """
        # 基础公共参数
        params = {
            "app_key": self.app_key,
            "method": "alibaba.offer.search",
            "timestamp": datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"),
            "v": "2.0",
            "format": "json"
        }
        # 业务参数(B2B批发核心)
        params["q"] = keyword.strip()
        params["pageNo"] = page_no
        params["pageSize"] = min(page_size, 40)  # 上限40
        if self.access_token:
            params["access_token"] = self.access_token
        if price_start:
            params["priceStart"] = price_start
        if price_end:
            params["priceEnd"] = price_end
        if min_order:
            params["minQuantity"] = min_order  # 起批量筛选
        if sort_type:
            params["sortType"] = sort_type
        if category_id:
            params["categoryId"] = category_id

        # 生成签名
        params["sign"], nonce = self._generate_sign(params)

        try:
            # 风控限速(关键防封)
            time.sleep(0.2)
            resp = self.session.post(self.base_url, data=params, timeout=15)
            result = resp.json()

            if not result.get("success"):
                return {"code": -1, "msg": f"接口错误:{result.get('errorMsg')}", "error": result}

            data = result.get("result", {})
            item_list = data.get("itemList", [])
            # 结构化解析(仅保留核心批发字段)
            product_list = []
            for item in item_list:
                product_list.append({
                    "offer_id": item.get("offerId"),
                    "title": item.get("subject"),
                    "main_image": item.get("imageUrl"),
                    "price": item.get("price"),  # 批发价
                    "min_order": item.get("minOrderQuantity"),  # 起批量
                    "sales": item.get("saleQuantity"),  # 销量
                    "supplier": item.get("company", {}).get("companyName"),
                    "category_id": item.get("categoryId")
                })

            return {
                "code": 200,
                "msg": "success",
                "data": {
                    "total": data.get("total", 0),
                    "page_no": page_no,
                    "page_size": page_size,
                    "product_list": product_list
                }
            }
        except Exception as e:
            return {"code": 500, "msg": f"异常:{str(e)}"}

# ———— 调用示例 ————
if __name__ == "__main__":
    api = AlibabaKeywordSearch(
        app_key="你的AppKey",
        app_secret="你的AppSecret",
        access_token="你的AccessToken"  # 公开搜索可注释
    )
    # 搜索"女装T恤",销量排序,价格10-50,起批量≥2
    res = api.search(
        keyword="女装T恤",
        page_no=1,
        page_size=20,
        price_start=10,
        price_end=50,
        min_order=2,
        sort_type="total"
    )
    print(json.dumps(res, ensure_ascii=False, indent=2))

四、实战避坑干货(原创)


  1. 签名必须带 nonce:百川 V2 强制随机串防重放,网上教程缺此参数导致签名失败。

  2. IP 白名单必配:开放平台添加服务器 IP,否则直接 403 禁止访问,多数教程遗漏。

  3. 起批量筛选用 minQuantity:B2B 批发核心参数,错写为 minOrder 会过滤失效。

  4. QPS 严格≤8:免费应用超频返回ISP_FLOW_CONTROL_LIMIT,批量分页间隔≥0.2s。

  5. 搜索结果仅摘要:offer.search 只返回基础数据,需用 offerId 调商品详情接口获取 SKU、阶梯价。

群贤毕至

访客