反向海淘系统最脏的输入:把用户粘贴的分享文案、淘口令、短链统一解析成商品 ID

admin2天前淘宝API11
反向海淘系统里,用户不会规规矩矩给你一条干净的详情页链接。他粘过来的可能是一整段带 emoji 的分享文案、一个 ¥xxxx¥ 淘口令、一段 m.tb.cn 短链,或者一条被跟踪参数污染到 200 字符的 URL。这篇讲我怎么把这件事做成一个稳定服务——解析链路、正则、短链展开、口令接口、缓存,以及把失败率从 12% 压到 1.5% 的全过程。

一、先盘点你实际要处理的输入长什么样

我在生产环境里捞了 500 条真实用户输入,粗分类如下:

形态
占比
示例特征
手机端分享文案
~38%
一大段中文 + 商品标题 + ¥abcd1234¥
标准详情页链接
~27%
detail.1688.com/offer/1234567890.html
短链
~18%
m.tb.cn/h.xxxxxx / 3.cn/xxxx
带跟踪参数的脏链接
~12%
尾部挂 ?spm=a1z10.5-c&scm=...&utm_...
图文混排(截图OCR、表格粘贴)
~5%
需要先抽文本

这五类输入的解析成本完全不同。所以第一件事不是写正则,而是先做形态判定,再分派给对应的解析器。

二、解析链路的五段设计

我把它拆成五段,每段只负责一件事,任何一段失败都能定位:
原始文本
  → ① 文本清洗(去 emoji / 去全角 / 统一换行)
  → ② 平台与形态判定(1688 / 淘宝 / 京东 / 未知)
  → ③ ID 抽取(正则)
  → ④ 兜底:短链展开 / 口令解析
  → ⑤ 统一输出 goods_id + platform

① 文本清洗

看起来最没技术含量,实际是最容易漏的。用户从 iOS 复制过来的文案里有:
  • 全角字符:? 以及全角数字 123
  • 零宽字符(U+200B / U+FEFF):肉眼看不见,但会把你的正则切断
  • emoji 与装饰符✨🛒 之类
  • 换行不统一\r\n / \r / \n 混用
import re, unicodedata

INVISIBLE = re.compile(r"[\u200b-\u200f\ufeff\u2060]")

def clean(text: str) -> str:
    text = INVISIBLE.sub("", text)
    text = "".join("\r" if c == "\n" else c for c in text.split("\r")[0:1]) + text
    text = text.replace("\r\n", "\n").replace("\r", "\n")
    text = unicodedata.normalize("NFKC", text)     # 全角转半角,一步搞定
    return text.strip()
unicodedata.normalize("NFKC", ...) 这一行值一百行手写替换代码,它能同时处理全角字母数字和兼容字符,强烈建议放在清洗链最前面。

② 平台判定

不要只靠域名判断——用户可能只粘了"【淘宝】"这样的前缀词。我的判定顺序是:显式域名 > 文本前缀词 > 兜底未知
PLATFORM_RULES = [
    ("1688",  r"(?:detail\.)?1688\.com|阿里巴巴|1688"),
    ("taobao", r"(?:item\.)?taobao\.com|m\.tb\.cn|天猫|淘宝|tmall"),
    ("jd",    r"(?:item\.)?jd\.com|3\.cn|京东|jd\.hk"),
]

def detect_platform(text):
    for name, pat in PLATFORM_RULES:
        if re.search(pat, text, re.I):
            return name
    return "unknown"

③ ID 抽取

三个平台的商品 ID 藏在完全不同的位置,这是最容易写错的一段:
ID_PATTERNS = {
    "1688":   r"offer/(\d{8,})",
    "taobao": r"[?&](?:id|itemId)=(\d{8,})",
    "jd":     r"(?:item\.jd\.com/|/product/)(\d{6,})",
}

def extract_id(platform, text):
    m = re.search(ID_PATTERNS[platform], text)
    return m.group(1) if m else None
注意 1688 有个坑:detail.1688.com/offer/1234567890.html 里的 ID 是报价 ID,而 item_get 接受的 num_iid 就是它,不用做转换;但淘宝的 num_iidsku_id 是两套东西,链接里带的是 num_iid千万别把京东的 sku_id 当成淘宝的 num_iid 传进同一个字段,我在早期版本把两者混用,导致一整个类目的详情全查不到。

④ 短链展开

短链没有 ID,只能先跟重定向。这里有两个必须做对的地方:
第一,用手机 UA。 同一个 m.tb.cn 链接,桌面 UA 请求可能被重定向到一个带登录引导的中间页,Location 里没有商品 ID;手机 UA 通常会直接落到 item.taobao.com/item.htm?id=...
第二,限制跳转次数并检查落点。 有的短链会先跳到活动落地页,再跳详情页,一次 HEAD 拿不到最终地址。
import requests

MOBILE_UA = ("Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) "
             "AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1")

def expand_short(url, max_hop=5):
    for _ in range(max_hop):
        r = requests.head(url, allow_redirects=False,
                          headers={"User-Agent": MOBILE_UA}, timeout=8)
        loc = r.headers.get("Location")
        if not loc:
            return url
        url = requests.compat.urljoin(url, loc)
        if re.search(r"item\.(taobao|jd)\.com|detail\.1688\.com", url):
            return url
    return url
短链展开的实测成功率并不高——3.cn 这类会有一定的跳转异常,所以我把展开失败的情况统一转入口令/链接转换接口。

⑤ 淘口令与链接转换

淘口令(¥xxxxxxxx¥)必须靠专用接口,正则解析不出来。淘宝平台的 item_password 后台统计成功率 95%,用来解口令是够用的;链接清洗与长短链互转用 item_link,它的成功率是 100%,是我这套链路里最稳的一环,我把它当"URL 归一化器"用——不管用户给的是淘客链、短链还是带一堆跟踪参数的长链,都先过一遍它。
def parse_password(text):
    url = "https://api-gw.onebound.cn/taobao/item_password"
    params = {
        "key": KEY, "secret": SECRET, "api_name": "item_password",
        "content": text,            # 直接传原始文案,接口自己找口令
        "result_type": "json",
    }
    r = requests.get(url, params=params, timeout=12).json()
    if r.get("code") != "0000":
        return None, r.get("code")
    return r.get("item", {}).get("num_iid"), "0000"

def normalize_link(link):
    url = "https://api-gw.onebound.cn/taobao/item_link"
    params = {"key": KEY, "secret": SECRET, "api_name": "item_link",
              "url": link, "result_type": "json"}
    return requests.get(url, params=params, timeout=12).json()
把口令和链接都归到 num_iid 之后,后面的详情、比价、加购链路就只需要面对一种入参。

三、四个花了两天才定位的坑

坑 1:& 被二次转义。 用户从浏览器复制来的链接里 & 可能已经是 &,你直接塞进 params 字典,requests 会把它再编码一次,服务端拿到的 id 值就带上了尾巴。做法是解析前先做一次 html.unescape
坑 2:淘口令有生命周期。 口令并不永久有效,过期后接口会返回业务失败。我给口令结果单独打了短 TTL(10 分钟)缓存,过期即失效,不做长缓存,避免用户拿到已失效的 ID。
坑 3:短链落到 landing page。 有些短链的落点是活动页,页面上有几十个商品链接。我的原则是只接受能唯一确定商品 ID 的落点,出现多个候选就判失败、转人工——选错商品的成本远高于多一次人工。
坑 4:cache 在这里要慎用。 解析类请求(item_link / item_password)我全部关掉缓存(cache=no),因为同一个短链在不同时间可能指向不同活动页;而详情接口(item_get)走缓存没问题。混用缓存策略是我早期最隐蔽的成本浪费来源。

四、落地成服务:缓存与指标

把上面的逻辑包成一个 POST /resolve 接口,入参是原始文本,出参是 {platform, goods_id, source}source 标记它是从正则、短链还是口令拿到的。
关键是在缓存层做一层 raw_text → goods_id 的映射,因为同一段分享文案会被多个客服/多个用户反复粘贴:
def resolve(raw, ttl=7 * 24 * 3600):
    key = "rsv:" + hashlib.md5(raw.encode()).hexdigest()
    if cached := redis.get(key):
        return json.loads(cached)
    result = do_resolve(raw)                     # 五段链路
    if result["goods_id"]:
        redis.setex(key, ttl, json.dumps(result))
    return result
上线前后我记录了一组数据,解析失败率从 12.3% 降到 1.5%。下降主要由三块贡献:NFKC 归一化解决了一批全角/零宽字符导致的"看起来有链接、其实抽不出 ID";item_link 接管了脏链接清洗;缓存把重复粘贴的解析请求从下游接口上摘掉了——命中率稳定在 60% 以上,也就是说超过一半的解析请求根本不到达网关层。
监控上我只看两个指标:source 分的解析成功率未知平台的原始文本采样。后者尤其有用——unknown 占比突然上升,通常意味着某个平台改了分享文案模板,比等接口大面积报错要早发现半天。
解析完成后,拿到 num_iid / sku_id 就该走详情了。这里提醒一句选型:1688 的 item_get(99%)可以放心做主链路;淘宝的 item_get 后台统计只有 40%,必须配降级;京东详情用 item_get_pro(78%),并且 不要碰它的 item_search(28%)。选错入口,前面解析做得再漂亮也没用。

五、写在最后

这套链路的价值在于:把不确定性收在入口处,让下游永远只面对一种干净的入参。 解析这件事没有巧劲,就是把清洗、判定、抽取、兜底、缓存五段各自做扎实,然后盯着指标慢慢补边界。
接口参数我参考的是 open.onebound.cn/help/api,测试 key 我是在开放平台的控制台申请的,入口放这里,需要的自取:API 控制台


相关文章

淘宝商品详情API应用场景解析:获取实时的商品价格

淘宝商品详情API应用场景解析:获取实时的商品价格

 编辑在电商数字化运营体系中,商品价格是连接商家、平台与用户的核心枢纽,实时、准确的价格数据直接影响定价策略、用户转化与市场竞争力。淘宝商品详情API作为淘宝开放平台(TOP)提供的核心数据...

淘宝评论API技术解析与调用实战指南

在电商数据分析、竞品监控、用户反馈挖掘等场景中,淘宝评论数据是极具价值的核心数据源。淘宝评论API作为获取这类数据的官方合规渠道,能够帮助开发者高效、稳定地获取商品评论相关信息。本文将从API基础概述...

企业级对接:淘宝商品详情 API 返回异常字段兼容与容错解析方案

前言在电商 SaaS、商品同步中台、竞品监控、反向海淘系统等企业级场景中,taobao.item_get 商品详情 API 是核心数据源。多数开发者仅做基础 JSON 取值,上线后频繁遭遇各类异常:嵌...

获取淘宝商品详情数据API对接完全指南

 本文提供淘宝商品详情数据的完整API对接方案,包含商品标题、价格、详情、主图、店铺等信息。1、获取商品价格详情API:item_get公共参数 (点此进入获取测试key)...

淘宝评论接口返回数据示例-响应参数说明

"items": {     "totalpage": 2,    ...

淘宝商品视频提取API全解析:从授权到落地实战

淘宝商品视频提取API全解析:从授权到落地实战

 编辑在电商数字化运营场景中,淘宝商品详情页的主图视频(通常9~30秒)因直观展示商品细节、提升转化效率的优势,成为比价平台搭建、选品数据分析、社媒内容投放等业务的核心素材。相较于非正规的爬...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。