Java爬虫淘宝拍立淘item_search_img拍接口示例代码

淘宝拍立淘(item_search_img)接口允许开发者上传一张商品图片,返回与之相似的商品列表,广泛用于比价、选品、竞品监控等场景。下面给出一份"纯 Java 版"爬取思路与示例代码,不依赖任何官方 SDK,也不带外链,方便快速集成到自有爬虫框架中。


一、核心流程

  1. 注册淘宝开放平台账号,创建应用,拿到 app_key / app_secret,并申请 taobao.item_search_img 权限。

  2. 把待搜索图片转成淘宝认可的"外部地址":

    • 方案 A:先调淘宝 pic/upload 接口拿到 imgId;

    • 方案 B:把图片直传 OSS/七牛等可公网访问的地址,复制 URL 即可。

  3. 按淘宝签名规范生成 sign(MD5,ASCII 升序 + app_secret 前后包夹)。

  4. 用 POST 方式提交到 eco.taobao.com/router/rest,Content-Type 为 application/x-www-form-urlencoded。

  5. 解析返回 JSON,提取 items→item 数组里的 title、price、pic_url、detail_url、sales 等字段。


二、关键参数

参数名 必填 说明
method 固定 taobao.item_search_img
app_key 应用唯一标识
timestamp 格式 yyyy-MM-dd HH:mm:ss
format json
v 2.0
sign_method md5
sign 按规范生成的签名
imgid 图片 URL(或 upload 后的 id)
cat 类目 ID,如 50010788 表示女装
page 页码,默认 1

三、Java 签名与请求示例

java 复制代码
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.*;
import org.json.JSONObject;

public class PailitaoCrawler {

    private static final String APP_KEY     = "your_app_key";
    private static final String APP_SECRET  = "your_app_secret";
    private static final String GATEWAY     = "https://eco.taobao.com/router/rest";

    public static void main(String[] args) throws Exception {
        String imgUrl = "https://your-domain.com/demo.jpg"; // 公网可访问
        String json   = searchByImage(imgUrl, 1);
        System.out.println(json);
    }

    public static String searchByImage(String imgUrl, int page) throws Exception {
        Map<String, String> params = new LinkedHashMap<>();
        params.put("method",       "taobao.item_search_img");
        params.put("app_key",      APP_KEY);
        params.put("timestamp",    new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        params.put("format",       "json");
        params.put("v",            "2.0");
        params.put("sign_method",  "md5");
        params.put("imgid",        imgUrl);
        params.put("page",         String.valueOf(page));

        String sign = generateSign(params, APP_SECRET);
        params.put("sign", sign);

        String body = buildQuery(params);
        return httpPost(GATEWAY, body);
    }

    private static String generateSign(Map<String, String> params, String secret) throws Exception {
        List<String> keys = new ArrayList<>(params.keySet());
        Collections.sort(keys);
        StringBuilder sb = new StringBuilder(secret);
        for (String k : keys) sb.append(k).append(params.get(k));
        sb.append(secret);
        byte[] bytes = MessageDigest.getInstance("MD5").digest(sb.toString().getBytes(StandardCharsets.UTF_8));
        StringBuilder hex = new StringBuilder();
        for (byte b : bytes) hex.append(String.format("%02X", b));
        return hex.toString();
    }

    private static String buildQuery(Map<String, String> params) throws Exception {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> e : params.entrySet()) {
            if (sb.length() > 0) sb.append('&');
            sb.append(e.getKey()).append('=')
              .append(URLEncoder.encode(e.getValue(), "UTF-8"));
        }
        return sb.toString();
    }

    private static String httpPost(String url, String body) throws Exception {
        java.net.HttpURLConnection conn = (java.net.HttpURLConnection) new java.net.URL(url).openConnection();
        conn.setRequestMethod("POST");
        conn.setDoOutput(true);
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        try (OutputStream os = conn.getOutputStream()) {
            os.write(body.getBytes(StandardCharsets.UTF_8));
        }
        try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
            StringBuilder res = new StringBuilder();
            String line;
            while ((line = br.readLine()) != null) res.append(line);
            return res.toString();
        }
    }
}

四、返回数据快速解析

返回片段示例(已格式化):

javascript 复制代码
{
  "item_search_img_response": {
    "items": {
      "item": [
        {
          "title": "日系宽松卫衣",
          "price": "89.00",
          "pic_url": "https://img.alicdn.com/xxx.jpg",
          "detail_url": "https://item.taobao.com/id=xxx",
          "sales": 1203
        }
      ]
    }
  }
}

用 org.json 或 fastjson 取出数组即可落地到数据库/ES。


五、常见踩坑

  1. sign 错误:确保 ASCII 升序、value 不编码、前后都带 secret。

  2. 图片地址防盗链:外部地址必须 200 且返回 image/*,否则淘宝会报 5001。

  3. 频率限制:默认 5000 次/日,超出会 403,需要缓存或队列削峰。

  4. 类目过滤:cat 传错会返回空列表,可先用 itemcats 接口拉全量映射表。

  5. 分页最多 100 页,每页 20 条,即 2000 条上限,深度翻页意义不大。

相关推荐
郝学胜-神的一滴2 小时前
Python数据模型:深入解析及其对Python生态的影响
开发语言·网络·python·程序人生·性能优化
一水鉴天2 小时前
整体设计 定稿 之26 重构和改造现有程序结构 之2 (codebuddy)
开发语言·人工智能·重构·架构
free-elcmacom2 小时前
机器学习进阶<8>PCA主成分分析
人工智能·python·机器学习·pca
star _chen2 小时前
C++ std::move()详解:从小白到高手
开发语言·c++
lzhdim3 小时前
C#开发者必知的100个黑科技(前50)!从主构造函数到源生成器全面掌握
开发语言·科技·c#
刺客xs3 小时前
Qt----事件简述
开发语言·qt
程序员-King.3 小时前
【Qt开源项目】— ModbusScope-进度规划
开发语言·qt
syt_10133 小时前
Object.defineProperty和Proxy实现拦截的区别
开发语言·前端·javascript
liu****3 小时前
Python 基础语法(二):程序流程控制
开发语言·python·python基础