×

DMM 关键词搜索 API:跨类目分页边界控制与搜索结果归一化方案

Ace Ace 发表于2026-09-10 16:35:55 浏览9 评论0

抢沙发发表评论

前言

DMM 联盟 ItemList 接口支持关键词检索全站商品,是日系选品系统的核心检索源。网上多数示例仅实现基础关键词请求,忽略该接口独有的限制:多业务 floor 类目隔离、offset 存在上限、日文关键词编码陷阱、不同类目返回字段异构、分页末尾会出现重复商品。本文不再做简单入门演示,聚焦跨类目批量检索、分页边界校验、结果去重、字段统一映射,封装一套适合后台检索任务的稳定实现。

点击获取key和secret

Python 完整代码

import requests
import urllib.parse
import time

class DmmKeywordSearchClient:
    def __init__(self, api_id, affiliate_id):
        self.api_id = api_id
        self.affiliate_id = affiliate_id
        self.base_url = "https://api.dmm.com/affiliate/v3/ItemList"
        self.seen_cid = set() # 全局CID去重

    def search_keyword(self, keyword, floor="book", site="DMM", hits=20, offset=1):
        # offset上限校验,超出直接返回空,规避接口报错
        if offset > 1000:
            return {"ok": False, "msg": "offset超出接口上限", "data": []}
        # 日文关键词URL编码
        keyword_encode = urllib.parse.quote(keyword)
        params = {
            "api_id": self.api_id,
            "affiliate_id": self.affiliate_id,
            "site": site,
            "floor": floor,
            "hits": hits,
            "offset": offset,
            "keyword": keyword_encode,
            "output": "json"
        }
        try:
            resp = requests.get(self.base_url, params=params, timeout=15)
            resp.raise_for_status()
            raw = resp.json()
        except Exception as e:
            return {"ok": False, "msg": f"请求异常:{str(e)}", "data": []}

        result = raw.get("result", {})
        item_list = result.get("items", [])
        clean_result = []
        for item in item_list:
            cid = item.get("cid")
            if not cid or cid in self.seen_cid:
                continue
            self.seen_cid.add(cid)
            item_out = {
                "cid": cid,
                "title": item.get("title", "").strip(),
                "price": item.get("price", ""),
                "maker": item.get("maker", {}).get("name", ""),
                "url": item.get("url", ""),
                "floor": item.get("floor", ""),
                "genres": [g.get("name", "") for g in item.get("genre", [])]
            }
            clean_result.append(item_out)
        return {"ok": True, "total": result.get("total",0), "data": clean_result}

if __name__ == "__main__":
    client = DmmKeywordSearchClient("你的API_ID", "你的联盟ID")
    res = client.search_keyword(keyword="ゲーム", floor="game", hits=20, offset=1)
    print(f"检索总数量:{res['total']}, 有效商品:{res['data']}")

核心设计思路


  1. Offset 边界保护:DMM 接口 offset 最大限制 1000,很多人写无限循环分页,到上限直接报错。代码提前拦截超限参数,避免批量任务崩溃。

  2. 日文关键词编码:日文检索词必须手动 URL 编码,直接传日文会出现检索为空的问题,这是高频踩坑点。

  3. CID 全局去重:接口分页尾部存在商品漂移,同一商品在不同 offset 重复返回,使用 cid 集合过滤重复数据。

  4. 跨 floor 字段兼容:图书、游戏、通贩等类目返回字段不一致,采用.get()安全取值,防止某个字段缺失直接抛出异常。


对接踩坑要点


  1. Affiliate 联盟 ID 末尾必须是 990~999,否则直接鉴权失败。

  2. floor 参数需要和 site 匹配,跨 floor 检索不能一次性完成,需要循环多个 floor 分别检索再合并结果。

  3. hits 单页上限 100,建议控制 20~50,单次请求量大更容易触发限流。批量检索必须添加请求间隔。

  4. 返回 total 仅为估算值,不能完全依靠 total 循环分页,需要判断返回 item 列表为空终止任务。

  5. 使用接口返回数据对外展示,需要遵守 DMM 联盟协议,添加官方版权声明。

群贤毕至

访客