一、概述
1688作为国内最大的B2B批发采购平台,拥有海量商品数据。对于电商开发者、选品工具和供应链系统而言,图片搜索(图搜/拍立淘)和关键词搜索是两种最高效的找货方式。本文将带你从0到1掌握1688图搜API和关键词搜索API的完整调用流程,附赠实战代码,让你的开发效率翻倍。
二、准备工作:账号与权限
2.1 注册1688开放平台账号
1688开放平台主要面向企业开发者,个人开发者权限受限。
- 访问 1688平台
- 使用企业支付宝账号注册并完成企业实名认证
- 提交营业执照、法人身份证等资质
2.2 创建应用获取凭证
在控制台创建应用后,你将获得:
- App Key:应用唯一标识
- App Secret:签名密钥(严格保密)
2.3 申请API权限
根据业务需求申请对应接口权限:
表格
| 接口类型 | 接口名称 | 功能描述 |
| 图搜API | alibaba.image.search |
上传图片搜索相似商品 |
| 关键词搜索 | com.alibaba.product.search / alibaba.wholesale.goods.search |
按关键词搜索商品列表 |
| 商品详情 | alibaba.product.get |
获取商品详细信息 |
| 店铺商品 | alibaba.product.getSellerProductList |
获取指定店铺全部商品 |
⚠️ 注意:部分接口需要通过OAuth2.0授权获取
access_token,特别是涉及店铺数据的操作。
三、签名生成机制
1688开放平台采用 HMAC-SHA1 或 MD5 签名算法,所有请求参数必须按规则生成签名。
3.1 签名规则
- 排序:将所有参数(除
sign外)按参数名 ASCII 码升序排列 - 拼接:格式为
appSecret + key1value1 + key2value2 + ... + appSecret - 加密:使用 MD5 加密,结果转大写
3.2 Python签名工具类
Python
import hashlib import hmac import time import urllib.parse from datetime import datetime class AlibabaApiSigner: """1688开放平台API签名工具类""" def __init__(self, app_key: str, app_secret: str): self.app_key = app_key self.app_secret = app_secret self.base_url = "https://api.1688.com/router/rest" def generate_md5_sign(self, params: dict) -> str: """ 生成MD5签名(适用于大多数1688接口) """ # 过滤空值和sign参数 filtered = {k: v for k, v in params.items() if v is not None and k != 'sign'} # 按key升序排列 sorted_items = sorted(filtered.items(), key=lambda x: x[0]) # 拼接字符串 sign_content = self.app_secret for key, value in sorted_items: sign_content += f"{key}{value}" sign_content += self.app_secret # MD5加密并转大写 return hashlib.md5(sign_content.encode('utf-8')).hexdigest().upper() def generate_hmac_sign(self, params: dict) -> str: """ 生成HMAC-SHA1签名(部分接口使用) """ filtered = {k: v for k, v in params.items() if v is not None and k != 'sign'} sorted_items = sorted(filtered.items(), key=lambda x: x[0]) sign_content = self.app_secret for key, value in sorted_items: sign_content += f"{key}{value}" sign_content += self.app_secret # HMAC-SHA1加密 sign = hmac.new( self.app_secret.encode('utf-8'), sign_content.encode('utf-8'), hashlib.sha1 ).hexdigest().upper() return sign def build_base_params(self) -> dict: """构建基础请求参数""" return { 'app_key': self.app_key, 'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'format': 'json', 'v': '2.0', 'sign_method': 'md5' }
四、关键词搜索商品API实战
4.1 接口概述
关键词搜索是1688最核心的找货方式,支持按关键词、价格区间、类目、排序等多维度筛选。
接口地址:https://api.1688.com/router/rest
请求方式:POST
数据格式:application/x-www-form-urlencoded
4.2 核心参数说明
表格
| 参数名 | 类型 | 必选 | 说明 |
method |
String | 是 | 接口方法名,如 com.alibaba.product.search |
app_key |
String | 是 | 应用Key |
sign |
String | 是 | 签名 |
timestamp |
String | 是 | 时间戳 |
q / keyword |
String | 是 | 搜索关键词 |
page / page_no |
Number | 否 | 页码,默认1 |
pageSize / page_size |
Number | 否 | 每页数量,默认20 |
priceStart |
Number | 否 | 价格区间起始 |
priceEnd |
Number | 否 | 价格区间结束 |
categoryId |
Number | 否 | 类目ID过滤 |
sort |
String | 否 | 排序方式:price_asc/price_desc/sale |
4.3 完整调用代码
Python
import requests import json import time from typing import List, Dict, Optional class AlibabaKeywordSearch: """1688关键词搜索商品API封装""" def __init__(self, app_key: str, app_secret: str): self.signer = AlibabaApiSigner(app_key, app_secret) self.api_url = "https://api.1688.com/router/rest" def search_products( self, keyword: str, page: int = 1, page_size: int = 20, price_start: Optional[float] = None, price_end: Optional[float] = None, category_id: Optional[int] = None, sort: str = "default" ) -> Dict: """ 关键词搜索商品 :param keyword: 搜索关键词,如"无线蓝牙耳机" :param page: 页码 :param page_size: 每页数量(建议不超过50) :param price_start: 最低价格 :param price_end: 最高价格 :param category_id: 类目ID过滤 :param sort: 排序方式 :return: 搜索结果字典 """ # 构建基础参数 params = self.signer.build_base_params() params['method'] = 'com.alibaba.product.search' # 或 alibaba.wholesale.goods.search # 业务参数 params['q'] = keyword params['page'] = page params['pageSize'] = page_size if price_start is not None: params['priceStart'] = price_start if price_end is not None: params['priceEnd'] = price_end if category_id is not None: params['categoryId'] = category_id if sort != "default": params['sort'] = sort # 生成签名 params['sign'] = self.signer.generate_md5_sign(params) # 发送请求 try: response = requests.post( self.api_url, data=params, headers={'Content-Type': 'application/x-www-form-urlencoded'}, timeout=30 ) response.raise_for_status() return response.json() except requests.RequestException as e: print(f"请求异常: {e}") return {"error": str(e)} def parse_search_results(self, response: Dict) -> List[Dict]: """ 解析搜索结果,提取关键字段 """ results = [] # 根据实际返回结构解析(不同接口返回结构可能不同) if 'result' in response: products = response['result'].get('result', []) elif 'productSearchResponse' in response: products = response['productSearchResponse'].get('products', []) else: # 适配不同返回结构 products = response.get('products', []) for product in products: item = { 'product_id': product.get('productId') or product.get('offerId'), 'title': product.get('subject') or product.get('title'), 'price': product.get('price') or product.get('salePrice'), 'image_url': product.get('imageUrl') or product.get('mainImage'), 'supplier_name': product.get('companyName') or product.get('supplier'), 'min_order': product.get('minOrderQuantity', 1), 'sale_count': product.get('saleCount', 0), 'detail_url': product.get('detailUrl', ''), 'location': product.get('location', '') } results.append(item) return results def batch_search( self, keywords: List[str], pages: int = 3, delay: float = 1.5 ) -> Dict[str, List[Dict]]: """ 批量关键词搜索(带限流控制) :param keywords: 关键词列表 :param pages: 每个关键词搜索页数 :param delay: 请求间隔(秒) :return: {keyword: [products]} """ all_results = {} for keyword in keywords: print(f"🔍 正在搜索: {keyword}") keyword_results = [] for page in range(1, pages + 1): response = self.search_products( keyword=keyword, page=page, page_size=50 ) products = self.parse_search_results(response) if not products: break keyword_results.extend(products) print(f" 第{page}页获取 {len(products)} 条数据") # 限流:避免触发QPS限制 if page < pages: time.sleep(delay) all_results[keyword] = keyword_results print(f"✅ {keyword} 共获取 {len(keyword_results)} 条数据\n") return all_results # ========== 实战演示 ========== if __name__ == '__main__': APP_KEY = 'your_app_key' APP_SECRET = 'your_app_secret' searcher = AlibabaKeywordSearch(APP_KEY, APP_SECRET) # 单关键词搜索 print("=" * 60) print("【单关键词搜索示例】") print("=" * 60) result = searcher.search_products( keyword="无线蓝牙耳机", page=1, page_size=10, price_start=10, price_end=100, sort="price_asc" ) products = searcher.parse_search_results(result) for i, p in enumerate(products[:5], 1): print(f"{i}. {p['title'][:30]}... | ¥{p['price']} | 销量:{p['sale_count']}") # 批量关键词搜索 print("\n" + "=" * 60) print("【批量关键词搜索示例】") print("=" * 60) keywords = ["T恤批发", "手机壳", "数据线", "保温杯"] batch_results = searcher.batch_search(keywords, pages=2, delay=2) for kw, items in batch_results.items(): print(f"📦 {kw}: {len(items)} 条商品")
五、图搜(以图搜货/拍立淘)API实战
5.1 接口概述
1688图搜API(拍立淘/以图搜货)是官方图像搜品接口,支持通过图片URL或Base64编码输入图片,秒级返回同款/相似商品的结构化数据。
核心能力:
- 上传商品图片 → 返回同款/相似商品
- 返回商品ID、标题、价格、供应商等结构化数据
- 支持图片URL或Base64两种输入方式
5.2 核心参数说明
表格
| 参数名 | 类型 | 必选 | 说明 |
method |
String | 是 | 接口方法名,如 alibaba.image.search |
image_url |
String | 条件 | 图片网络URL(与image_content二选一) |
image_content |
String | 条件 | 图片Base64编码(与image_url二选一) |
category_id |
Number | 否 | 指定搜索类目,提高精准度 |
keyword |
String | 否 | 配合图片的关键词辅助搜索 |
5.3 完整调用代码
Python
import base64 import requests from typing import Optional class AlibabaImageSearch: """1688图搜(拍立淘)API封装""" def __init__(self, app_key: str, app_secret: str): self.signer = AlibabaApiSigner(app_key, app_secret) self.api_url = "https://api.1688.com/router/rest" def search_by_url( self, image_url: str, category_id: Optional[int] = None, keyword: Optional[str] = None ) -> dict: """ 通过图片URL搜索商品 :param image_url: 图片的网络地址 :param category_id: 指定类目ID(可选) :param keyword: 辅助关键词(可选) :return: 搜索结果 """ params = self.signer.build_base_params() params['method'] = 'alibaba.image.search' params['image_url'] = image_url if category_id: params['category_id'] = category_id if keyword: params['keyword'] = keyword params['sign'] = self.signer.generate_md5_sign(params) try: response = requests.post( self.api_url, data=params, timeout=30 ) return response.json() except Exception as e: return {"error": str(e)} def search_by_file( self, image_path: str, category_id: Optional[int] = None, keyword: Optional[str] = None ) -> dict: """ 通过本地图片文件搜索商品(Base64编码上传) :param image_path: 本地图片路径 :param category_id: 指定类目ID :param keyword: 辅助关键词 :return: 搜索结果 """ # 读取图片并Base64编码 try: with open(image_path, 'rb') as f: image_bytes = f.read() image_base64 = base64.b64encode(image_bytes).decode('utf-8') except Exception as e: return {"error": f"图片读取失败: {e}"} params = self.signer.build_base_params() params['method'] = 'alibaba.image.search' params['image_content'] = image_base64 if category_id: params['category_id'] = category_id if keyword: params['keyword'] = keyword params['sign'] = self.signer.generate_md5_sign(params) try: response = requests.post( self.api_url, data=params, timeout=60 # 图搜可能需要更长时间 ) return response.json() except Exception as e: return {"error": str(e)} def parse_image_results(self, response: dict) -> list: """ 解析图搜结果 """ results = [] # 适配不同返回结构 if 'imageSearchResponse' in response: items = response['imageSearchResponse'].get('items', []) elif 'result' in response: items = response['result'].get('items', []) else: items = response.get('items', []) for item in items: result = { 'product_id': item.get('productId') or item.get('offerId'), 'title': item.get('subject') or item.get('title'), 'price': item.get('price'), 'image_url': item.get('imageUrl') or item.get('mainImage'), 'similarity': item.get('similarity', 0), # 相似度分数 'supplier': item.get('companyName') or item.get('supplier'), 'detail_url': item.get('detailUrl', ''), 'min_order': item.get('minOrderQuantity', 1) } results.append(result) return results # ========== 图搜实战演示 ========== if __name__ == '__main__': APP_KEY = 'your_app_key' APP_SECRET = 'your_app_secret' image_searcher = AlibabaImageSearch(APP_KEY, APP_SECRET) print("=" * 60) print("【图搜实战:通过图片URL搜索】") print("=" * 60) # 方式1:通过图片URL搜索 image_url = "https://example.com/your-product-image.jpg" result = image_searcher.search_by_url( image_url=image_url, category_id=1512, # 可选:限定在手机数码类目 keyword="蓝牙耳机" ) items = image_searcher.parse_image_results(result) print(f"找到 {len(items)} 个相似商品:") for i, item in enumerate(items[:5], 1): print(f"{i}. {item['title'][:35]}... | ¥{item['price']} | 相似度:{item['similarity']}%") # 方式2:通过本地文件搜索 print("\n" + "=" * 60) print("【图搜实战:通过本地图片文件搜索】") print("=" * 60) # result = image_searcher.search_by_file( # image_path="/path/to/your/image.jpg", # keyword="手机壳" # ) # items = image_searcher.parse_image_results(result)
六、高级实战:关键词+图搜组合策略
6.1 组合搜索场景
在实际业务中,单一搜索方式往往不够精准。以下是几种高效的组合策略:
表格
| 场景 | 策略 | 效果 |
| 找同款货源 | 先关键词搜索 → 用图搜验证 | 精准定位源头工厂 |
| 竞品分析 | 图搜找到竞品 → 关键词搜索同类 | 全面了解市场行情 |
| 价格监控 | 图搜锁定商品 → 定期关键词比价 | 实时跟踪价格波动 |
| 选品拓展 | 关键词发现趋势 → 图搜找相似款 | 快速扩展产品线 |
6.2 组合搜索实战代码
Python
class AlibabaSearchCombo: """1688组合搜索策略:关键词+图搜联动""" def __init__(self, app_key: str, app_secret: str): self.keyword_searcher = AlibabaKeywordSearch(app_key, app_secret) self.image_searcher = AlibabaImageSearch(app_key, app_secret) def find_source_factory(self, product_title: str) -> list: """ 找同款货源:先关键词搜索,再用图搜验证 :param product_title: 商品标题 :return: 源头工厂列表 """ print(f"🔍 步骤1:关键词搜索 '{product_title}'") # 第一步:关键词搜索获取候选商品 kw_result = self.keyword_searcher.search_products( keyword=product_title, page=1, page_size=10, sort="sale" # 按销量排序 ) candidates = self.keyword_searcher.parse_search_results(kw_result) if not candidates: return [] # 取第一个商品的图片进行图搜 first_product = candidates[0] image_url = first_product.get('image_url') if not image_url: return candidates print(f"🖼️ 步骤2:用图搜验证 '{first_product['title'][:20]}...'") # 第二步:图搜找同款 img_result = self.image_searcher.search_by_url( image_url=image_url, keyword=product_title.split()[0] # 取第一个词作为辅助关键词 ) similar_items = self.image_searcher.parse_image_results(img_result) # 合并结果,去重 all_items = candidates + similar_items seen_ids = set() unique_items = [] for item in all_items: pid = item.get('product_id') if pid and pid not in seen_ids: seen_ids.add(pid) unique_items.append(item) # 按价格升序排列(找最便宜的源头) unique_items.sort(key=lambda x: float(x.get('price', 0) or 0)) return unique_items def price_comparison(self, image_url: str, keyword: str) -> dict: """ 价格监控:图搜锁定商品 + 关键词搜索比价 :param image_url: 商品图片URL :param keyword: 商品关键词 :return: 比价结果 """ # 图搜获取同款 img_result = self.image_searcher.search_by_url(image_url, keyword=keyword) image_items = self.image_searcher.parse_image_results(img_result) # 关键词搜索获取同类 kw_result = self.keyword_searcher.search_products( keyword=keyword, page=1, page_size=50 ) keyword_items = self.keyword_searcher.parse_search_results(kw_result) # 价格分析 all_prices = [] for item in image_items + keyword_items: price = item.get('price') if price and isinstance(price, (int, float)): all_prices.append(float(price)) if not all_prices: return {"error": "未获取到价格数据"} return { "image_search_count": len(image_items), "keyword_search_count": len(keyword_items), "min_price": min(all_prices), "max_price": max(all_prices), "avg_price": round(sum(all_prices) / len(all_prices), 2), "median_price": round(sorted(all_prices)[len(all_prices)//2], 2), "cheapest_item": min(image_items + keyword_items, key=lambda x: float(x.get('price', float('inf')) or float('inf'))) } # ========== 组合搜索实战 ========== if __name__ == '__main__': APP_KEY = 'your_app_key' APP_SECRET = 'your_app_secret' combo = AlibabaSearchCombo(APP_KEY, APP_SECRET) # 实战1:找同款货源 print("=" * 60) print("【实战1:找同款货源】") print("=" * 60) sources = combo.find_source_factory("无线蓝牙耳机 降噪") print(f"找到 {len(sources)} 个源头:") for i, s in enumerate(sources[:5], 1): print(f"{i}. {s['title'][:30]}... | ¥{s['price']} | {s['supplier']}") # 实战2:价格监控 print("\n" + "=" * 60) print("【实战2:价格监控】") print("=" * 60) # price_analysis = combo.price_comparison( # image_url="https://example.com/product.jpg", # keyword="蓝牙耳机" # ) # print(f"最低价格: ¥{price_analysis['min_price']}") # print(f"平均价格: ¥{price_analysis['avg_price']}") # print(f"最便宜的商品: {price_analysis['cheapest_item']['title']}")
七、性能优化与效率翻倍技巧
7.1 分页与批量处理
Python
class BatchProcessor: """批量处理优化""" def __init__(self, searcher: AlibabaKeywordSearch): self.searcher = searcher def fetch_all_pages( self, keyword: str, max_pages: int = 10, page_size: int = 50, delay: float = 1.2 ) -> list: """ 获取关键词的所有分页数据 :param max_pages: 最大页数 :param delay: 请求间隔(遵守QPS限制) """ all_products = [] for page in range(1, max_pages + 1): result = self.searcher.search_products( keyword=keyword, page=page, page_size=page_size ) products = self.searcher.parse_search_results(result) if not products: break all_products.extend(products) print(f" 第{page}页: {len(products)}条,累计:{len(all_products)}条") # 智能延时:根据返回数据量调整 time.sleep(delay) return all_products
7.2 缓存策略
Python
import json from functools import lru_cache class CachedSearcher(AlibabaKeywordSearch): """带缓存的搜索器""" def __init__(self, app_key: str, app_secret: str, cache_file: str = "search_cache.json"): super().__init__(app_key, app_secret) self.cache_file = cache_file self._load_cache() def _load_cache(self): try: with open(self.cache_file, 'r', encoding='utf-8') as f: self.cache = json.load(f) except FileNotFoundError: self.cache = {} def _save_cache(self): with open(self.cache_file, 'w', encoding='utf-8') as f: json.dump(self.cache, f, ensure_ascii=False, indent=2) def search_products(self, **kwargs): cache_key = json.dumps(kwargs, sort_keys=True) if cache_key in self.cache: print("📦 命中缓存") return self.cache[cache_key] result = super().search_products(**kwargs) self.cache[cache_key] = result self._save_cache() return result
7.3 并发请求(注意QPS限制)
Python
from concurrent.futures import ThreadPoolExecutor, as_completed def parallel_search(searcher, keywords: list, max_workers: int = 3) -> dict: """ 并发搜索多个关键词(需确保不超过QPS限制) :param max_workers: 并发数,建议不超过3 """ results = {} with ThreadPoolExecutor(max_workers=max_workers) as executor: future_to_kw = { executor.submit(searcher.search_products, kw, page=1, page_size=20): kw for kw in keywords } for future in as_completed(future_to_kw): kw = future_to_kw[future] try: result = future.result() results[kw] = searcher.parse_search_results(result) except Exception as e: results[kw] = {"error": str(e)} return results
八、错误处理与常见问题
8.1 常见错误码
表格
| 错误码 | 说明 | 解决方案 |
isv.invalid-parameter |
参数错误 | 检查必填参数和格式 |
isv.permission-api-forbidden |
API权限不足 | 申请对应接口权限 |
isv.permission-ip-limit |
IP受限 | 配置服务器IP白名单 |
isp.call-limited |
调用频率超限 | 降低QPS,增加延时 |
isv.invalid-signature |
签名错误 | 检查签名算法和参数排序 |
isv.item-not-exist |
商品不存在 | 检查商品ID是否有效 |
8.2 完整错误处理封装
Python
class ApiErrorHandler: """API错误处理工具""" @staticmethod def handle_response(response: dict) -> dict: """ 统一处理API响应 """ if 'error_response' in response: error = response['error_response'] code = error.get('code', 'unknown') msg = error.get('msg', '未知错误') error_map = { 'isv.invalid-signature': "签名错误,请检查App Secret和签名算法", 'isv.permission-api-forbidden': "API权限不足,请在开放平台申请权限", 'isp.call-limited': "调用频率超限,请降低请求频率", 'isv.invalid-parameter': f"参数错误: {msg}", } return { 'success': False, 'error_code': code, 'error_msg': error_map.get(code, msg), 'raw': response } return {'success': True, 'data': response}
九、总结
表格
| 能力 | 关键词搜索 | 图搜(拍立淘) |
| 输入方式 | 文字关键词 | 图片URL/Base64 |
| 适用场景 | 批量找货、市场分析 | 找同款、竞品追踪 |
| 精准度 | 依赖关键词质量 | 图像匹配,更精准 |
| 返回速度 | 快(秒级) | 稍慢(需图像处理) |
| 最佳实践 | 组合使用,先用关键词筛选,再用图搜验证 |