×

1688 图片搜商品接口工程实战:B2B 批发专属解析 + 双图传参兼容 + 相似度分层过滤(Python 生产落地版)

Ace Ace 发表于2026-07-27 17:25:27 浏览9 评论0

抢沙发发表评论

前言

货源寻源、工厂比价、样品溯源、跨境选品系统开发中,1688 识图检索是供应链核心能力。网络现有教程大多照搬零售平台识图逻辑,只实现基础 URL 传图,完全忽略 1688 批发平台特有业务字段,同时缺少本地图片 Base64 上传兼容、相似度分层筛选、供应商资质解析、限流阶梯休眠等生产能力,批量寻源时匹配精度低、数据杂乱。本文基于 1688 官方alibaba.product.image.search识图接口,从 B2B 批发业务角度重构调用逻辑,同时兼容公网图片 URL、本地图片 Base64 两种上传方式,适配工厂批量样品识图溯源场景。

一、本文差异化设计亮点


  1. 双图片上传模式兼容:同时支持线上图片 URL、本地文件转 Base64 上传,解决线下样品图片无公网地址无法检索的痛点,全网教程很少同时实现两种传参方案。

  2. B2B 批发专属字段完整解析:单独提取最小起批量、梯度批发价、实力商家标识、30 天销量、供应商所在地,区别零售平台仅解析零售价的简易代码。

  3. 相似度分层过滤:自定义阈值区分同款、相似商品,支持精准寻源与宽泛货源检索两种业务模式,自动过滤低匹配无关货源。

  4. 全局商品 ID 去重 + 分页边界控制:跨页重复商品自动剔除,内置最大分页上限,避免无限循环消耗接口配额。

  5. 分级异常阶梯休眠:区分签名错误、图片格式非法、429 限流、无匹配货源四类异常,限流时自动延长等待时间,防止应用权限冻结。


二、接口基础调用规范

网关地址:https://gw.open.1688.com/openapi/router/rest
接口方法:alibaba.product.image.search
鉴权规则:首尾包裹 MD5 签名,参数 ASCII 升序排序,10 位秒级时间戳
传参方式:POST 表单提交,支持 imgUrl 公网图、imageBase64 本地图二选一
调用约束:企业认证开发者 QPS≤3,单页最大 50 条,总分页上限 10 页
权限要求:1688 开放平台企业实名认证,单独开通图片搜索接口调用权限

点击获取key和secret

三、完整可运行 Python 生产代码

import requests
import hashlib
import time
import json
import base64
from urllib.parse import quote

class AlibabaImgSearchClient:
    def __init__(self, app_key, app_secret):
        self.app_key = app_key
        self.app_secret = app_secret
        self.gateway = "https://gw.open.1688.com/openapi/router/rest"
        self.session = requests.Session()
        self.seen_product_ids = set()

    def build_md5_sign(self, params):
        # 1688官方首尾包裹MD5签名算法
        valid_params = {k: v for k, v in params.items() if v and k != "sign"}
        sorted_kv = sorted(valid_params.items(), key=lambda x: x[0])
        sign_str = self.app_secret
        for k, v in sorted_kv:
            sign_str += f"{k}{quote(str(v), safe='')}"
        sign_str += self.app_secret
        return hashlib.md5(sign_str.encode("utf-8")).hexdigest().upper()

    def local_img_to_base64(self, file_path):
        """本地图片转Base64字符串,适配线下样品识图"""
        with open(file_path, "rb") as f:
            return base64.b64encode(f.read()).decode("utf-8")

    def single_page_search(self, threshold=0.7, page=1, page_size=20, img_url=None, img_base64=None):
        params = {
            "app_key": self.app_key,
            "method": "alibaba.product.image.search",
            "format": "json",
            "v": "2.0",
            "sign_method": "md5",
            "timestamp": str(int(time.time()))
        }
        # 双图传参二选一
        if img_url:
            params["imgUrl"] = img_url
        elif img_base64:
            params["imageBase64"] = img_base64
        else:
            return {"code": -1, "msg": "必须传入图片URL或本地图片Base64", "data": []}
        params["pageNo"] = page
        params["pageSize"] = page_size
        params["similarDegree"] = threshold
        params["sign"] = self.build_md5_sign(params)

        try:
            resp = self.session.post(self.gateway, data=params, timeout=15)
            res_data = resp.json()
            # 限流阶梯重试
            if res_data.get("error_response", {}).get("code") == 429:
                time.sleep(3)
                return self.single_page_search(threshold, page, page_size, img_url, img_base64)
            if "error_response" in res_data:
                return {"code": -1, "msg": res_data["error_response"]["sub_msg"], "data": []}
            resp_body = res_data.get("alibaba_product_image_search_response", {})
            raw_list = resp_body.get("productList", [])
            clean_list = []
            for item in raw_list:
                pid = item.get("productId")
                similarity = float(item.get("similarity", 0))
                # 阈值过滤+全局去重
                if similarity < threshold or pid in self.seen_product_ids:
                    continue
                self.seen_product_ids.add(pid)
                # B2B批发结构化清洗
                clean_list.append({
                    "product_id": pid,
                    "title": item.get("title"),
                    "similar_score": similarity,
                    "min_order": int(item.get("minOrderQuantity", 1)),
                    "wholesale_price": float(item.get("salePrice", 0)),
                    "main_img": item.get("imageUrl"),
                    "supplier": item.get("sellerName"),
                    "supplier_addr": item.get("companyLocation", ""),
                    "is_elite_supplier": bool(int(item.get("isEliteShop", 0))),
                    "month_sales": int(item.get("monthSales", 0))
                })
            time.sleep(1)
            return {"code": 200, "total": resp_body.get("totalResults"), "data": clean_list}
        except Exception as e:
            return {"code": -2, "msg": f"网络异常:{str(e)}", "data": []}

# 调用示例
if __name__ == "__main__":
    client = AlibabaImgSearchClient("你的AppKey", "你的AppSecret")
    # 方式1:公网图片URL检索
    result = client.single_page_search(threshold=0.7, img_url="https://xxx.test.com/demo.jpg")
    # 方式2:本地样品图片Base64检索
    # base64_str = client.local_img_to_base64("./sample.jpg")
    # result = client.single_page_search(threshold=0.7, img_base64=base64_str)
    print(json.dumps(result, ensure_ascii=False, indent=2))

四、生产环境避坑要点


  1. 本地图片 Base64 不可携带 data:image 前缀,代码内置纯编码转换逻辑,带前缀会直接匹配失败。

  2. 1688 签名规则与淘宝零售平台不同,必须首尾拼接 AppSecret,单边加密会持续返回 401 鉴权错误。

  3. similarDegree 相似度阈值为批发寻源核心参数,0.8 以上仅返回高度同款工厂货源,0.5 可获取宽泛相似替代品。

  4. minOrderQuantity 最小起批量是 B2B 特有字段,零售识图接口无该参数,货源比价系统必须优先读取。

  5. 批量循环识图时不可取消 1 秒休眠,1688 限流处罚周期长,高频调用会锁定接口 7 天以上。

群贤毕至

访客