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

admin4周前淘宝API100
反向海淘系统里,用户不会规规矩矩给你一条干净的详情页链接。他粘过来的可能是一整段带 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_iid 和 sku_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返回数据(部分)"item": {        "num_iid&q...

获取淘宝商品视频API接口解析:通过商品链接url获取商品视频item_video

获取淘宝商品视频API接口解析:通过商品链接url获取商品视频item_video

 请求代码示例# coding:utf-8""" Compatible for python2.x and ...

闲鱼商品搜索商品详情数据API调用指南

 item_search 关键字获取商品列表item_get  通过商品id获取商品详情数据下面演示通过item_search获取闲鱼扫地机的商品列表,响应数据如下:"i...

免 TOP 入驻,第三方淘宝商品详情 API 快速接入与代码示例

摘要:淘宝官方TOP开放平台存在入驻审核严苛、应用配置繁琐、签名规则复杂、部分数据权限受限、调用额度有限等问题,极大提升了中小开发者、初创项目的接入门槛。本文聚焦免TOP入驻、零签名配置、开箱即用的第...

关键字搜索天猫商品列表API调用示例分享

 item_search_tmall-按关键字搜索天猫商品用API搜索“女装”,返回结果如下:"page": "1", "real...

发表评论    

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