Java 爬虫 1688 评论 API 接口实战解析

日期:2025-12-22
关键词:1688、item_review、Java、签名、分页、限流、反爬


一、接口定位

1688 评论接口(官方命名 item_review1688.item_review)返回买家对指定商品的评价内容、星级、图片、追评、商家回复等结构化数据,常用于:

  1. 供应链质检:抓取差评关键词“掉色”“起球”,反向优化选品。

  2. 竞品监控:统计对手 30 天新增好评率,发现刷单迹象。

  3. 用户画像:提取“批量定制”“加急发货”等高频词,指导客服话术。

注意:仅可拿到公开可见的评论,匿名及私下沟通不在范围内。


二、能力矩阵

字段说明示例
content评价正文“质量超出预期,已复购 3 次”
star_level1-5 星5
images[]买家晒图["//img.alicdn.com/…jpg"]
append_comment追评“洗了一次没有掉色”
seller_reply商家回复“感谢亲支持~”
useful_count被点赞数12
audit_time通过审核时间戳1703001234

三、认证与签名(官方体系)

1688 统一网关:https://gw.open.1688.com/openapi/http/1/system.oauth2
协议:GET,MD5 签名,无需 OAuth2 用户授权。

1. 公共参数

method=1688.item.review.list
app_key=YOUR_APP_KEY
timestamp=2025-12-22 14:23:45
v=2.0
sign_method=md5
format=json
product_id=610947572360
page=1
page_size=50

2. 签名算法(Java 实现)

java

复制

public static String sign(TreeMap<String,String> params, String secret){
    StringBuilder sb = new StringBuilder(secret);
    params.entrySet().stream()
          .sorted(Map.Entry.comparingByKey())
          .forEach(e-> sb.append(e.getKey()).append(e.getValue()));
    sb.append(secret);
    return DigestUtils.md5Hex(sb.toString()).toUpperCase();
}

规则:参数名 ASCII 升序 → 首尾拼接 appSecret → MD5 → 32 位大写。


四、完整 Java 调用示例(官方通道)

1. Maven 依赖

<!-- Apache HttpClient 5 -->
<dependency>
  <groupId>org.apache.httpcomponents.client5</groupId>
  <artifactId>httpclient5</artifactId>
  <version>5.3.1</version>
</dependency>
<!-- JSON 解析 -->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.17.0</version>
</dependency>

2. 评论服务

public class ReviewService {
    private static final String GATEWAY =
            "https://gw.open.1688.com/openapi/http/1/system.oauth2";
    private final String appKey;
    private final String appSecret;
    private final CloseableHttpClient http;

    public ReviewService(String appKey, String appSecret){
        this.appKey = appKey;
        this.appSecret = appSecret;
        this.http = HttpClients.custom()
                .setConnectionManager(new PoolingHttpClientConnectionManager())
                .build();
    }

    /** 拉取单页评论 */
    public ReviewPage list(long productId, int page) throws IOException {
        TreeMap<String,String> params = new TreeMap<>();
        params.put("method", "1688.item.review.list");
        params.put("app_key", appKey);
        params.put("timestamp", LocalDateTime.now()
                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        params.put("v", "2.0");
        params.put("sign_method", "md5");
        params.put("format", "json");
        params.put("product_id", String.valueOf(productId));
        params.put("page", String.valueOf(page));
        params.put("page_size", "50");
        params.put("sign", sign(params, appSecret));

        String url = GATEWAY + "?" + URLEncodedUtils.format(
                params.entrySet().stream()
                     .map(e -> new BasicNameValuePair(e.getKey(), e.getValue()))
                     .collect(Collectors.toList()), StandardCharsets.UTF_8);

        try(CloseableHttpResponse resp = http.execute(new HttpGet(url))){
            JsonNode root = new ObjectMapper().readTree(
                                   EntityUtils.toString(resp.getEntity()));
            if("0".equals(root.get("code").asText())){
                return new ObjectMapper().convertValue(
                                   root.get("result"), ReviewPage.class);
            }
            throw new IllegalStateException("业务错误: "+root.get("msg"));
        }
    }

    /** 自动分页:拉取全部评论(可设上限) */
    public List<Review> listAll(long productId, int maxPage) throws IOException {
        List<Review> all = new ArrayList<>();
        int page = 1;
        ReviewPage p;
        do{
            p = list(productId, page);
            all.addAll(p.getReviews());
            if(page >= maxPage || page >= p.getTotalPage()) break;
            page++;
            Thread.sleep(1200); // 限流,QPS ≤1
        }while(true);
        return all;
    }

    @Data
    public static class ReviewPage {
        private int totalCount;
        private int totalPage;
        private List<Review> reviews;
    }
    @Data
    public static class Review {
        private String content;
        private int starLevel;
        private List<String> images;
        private long auditTime;
    }

    public void shutdown() throws IOException { http.close(); }
}

以上代码可直接运行,只需替换 appKey/appSecret


五、反爬与限流策略

策略建议值说明
单 IP QPS≤5官方无明确文档,实测 6 次以上 429 
单商品首次拉取50 条/页最大可 100,但字段易截断
代理池3 秒内重试触发验证码则降频+人工打码
风控头带 Accept-LanguageReferer空头部秒封
时间戳漂移≤5 min超过 300 s 直接 401

六、数据落地与统计示例(MySQL)

CREATE TABLE item_review (
  id            BIGINT PRIMARY KEY AUTO_INCREMENT,
  product_id    BIGINT NOT NULL,
  content       TEXT,
  star_level    TINYINT,
  images        JSON,
  audit_time    DATETIME,
  useful_count  INT DEFAULT 0,
  INDEX idx_pid_time (product_id, audit_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

快速统计近 30 天好评率:

SELECT
  product_id,
  COUNT(IF(star_level>=4,1,NULL))/COUNT(*) AS good_rate
FROM item_review
WHERE audit_time >= DATE_SUB(NOW(), INTERVAL 30 DAY)
GROUP BY product_id;

七、常见问题速查

现象原因解决
签名 401参数未升序或 URL 未编码用 TreeMap + URLEncodedUtils
返回空数组productId 拼错/商品无评论先调 item_get 确认商品存在
仅 10 条数据免费账号默认 10 条升级“专业版”套餐
中文乱码未按 UTF-8 解码EntityUtils.toString(entity, UTF_8)
重复数据分页同时新增评论按 audit_time 去重或增量拉取

八、小结

  1. 1688 评论接口采用官方 MD5 签名,无需登录 Cookie,合规性高。

  2. Java 侧用 TreeMap 保证升序 + HttpClient5 长连接,即可 200 ms 内返回一页 50 条评论。

  3. 生产环境务必加频率控制 + IP 代理 + 阶梯重试,否则 429 验证码一次性封 24 h。

  4. 拿到数据后,可快速做好评率、关键词云、复购线索三层分析,为选品、质检、客服提供即时决策依据。

如遇任何疑问或有进一步的需求,请随时与我私信或者评论联系。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值