限时福利领取


AI辅助开发实战:如何高效构建商城智能客服数据集下载系统

配图

摘要:本文针对电商场景下智能客服训练数据获取难的痛点,提出基于Python+Scrapy的自动化解决方案。通过逆向工程分析接口协议、分布式爬虫架构设计、以及数据清洗流水线实现,开发者可快速获取结构化对话数据。文中包含完整的反爬对抗策略和性能优化方案,数据采集效率提升300%的同时确保合法合规。

一、背景痛点:为什么商城客服数据这么难拿?

做智能客服的同学都懂,真正缺的不是模型,而是高质量对话数据。商城后台的聊天记录往往有三道锁:

  1. 前端接口动态加密,参数里带一次性Token,15分钟失效
  2. 频率限制极狠,单IP>60次/分钟直接弹验证码
  3. 数据结构异构,同一句话在JSON里可能叫content,也可能叫txt,甚至藏在HTML注释里

手工导出?运营同学给你个500条就顶天了。让算法同学拿这点点数据蒸馏BERT,简直是让小学生参加高考。于是“自动化、成规模、结构化”就成了刚需。

二、技术方案:为什么最后选了Scrapy+Rotating Proxy?

先把主流方案拉出来遛一遛:

技术栈 优点 缺点 结论
Requests+BeautifulSoup 上手快,调试方便 无并发、无中间件、反爬弱 放弃
Puppeteer/Playwright 能跑完整浏览器,破解JS加密牛 资源吃紧,单机并发低,成本高 备用,专门对付极端加密页面
Scrapy 原生异步、中间件丰富、扩展分布式容易 学习曲线略陡 主力框架

再配一把Rotating Proxy池(这里用国内厂商“站大爷”+自建代理池混拨),把60次/分钟拆拆成600次/分钟,单机的瓶颈瞬间消失。最终组合:

Scrapy + Rotating Proxy + Redis去重 + Kafka队列 → 数据湖

三、核心实现:关键代码片段全注释

下面代码均基于Python 3.8,配置项走环境变量,方便CI/CD直接注入。

1. 随机UA+请求间隔中间件

middlewares.py里加一段:

import random, os, time
from scrapy import signals

class RandomDelayMiddleware:
    def __init__(self):
        # 最小间隔读环境变量,默认0.8s
        self.delay_min = float(os.getenv("SCRAPY_DELAY_MIN", 0.8))
        self.delay_max = float(os.getenv("SCRAPY_DELAY_MAX", 2.3))

    def process_request(self, request, spider):
        delay = random.uniform(self.delay_min, self.delay_max)
        time.sleep(delay)
        return None

class RotateUserAgentMiddleware:
    ua_list = [
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64)...",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 12_3)...",
        # 更多略
    ]
    def process_request(self, request, spider):
        request.headers["User-Agent"] = random.choice(self.ua_list)
        return None

别忘了在settings.py里启用:

DOWNLOADER_MIDDLEWARES = {
   "project.middlewares.RandomDelayMiddleware": 300,
   "project.middlewares.RotateUserAgentMiddleware": 400,
}

2. XPath+正则混合解析

商城对话接口返回的JSON外层包了一层HTML,得先剥壳再取核:

import re, json
from scrapy import Selector

def extract_dialog(response):
    sel = Selector(response)
    # 先XPath抓脚本块
    script = sel.xpath("//script[contains(.,'window.__DATA')]/text()").get("")
并非是纯JSON,前面有多余变量赋值
    json_part = re.search(r"window\.__DATA\s*=\s*({.*?});", script, re.S)
    if not json_part:
        return []
    data = json.loads(json_part.group(1))
    # 取对话数组
    return [msg["content"] for msg in data.get("messageList", [])]

3. 基于MD5的去重

Scrapy自带RFPDupeFilter只能过滤URL,这里我们要对对话内容去重:

import hashlib
from scrapy.dupefilters import BaseDupeFilter

class ContentMD5DupeFilter(BaseDupeFilter):
    def __init__(self):
        self.seen = set()

    @classmethod
    def from_settings(cls, settings):
        return cls()

    def request_seen(self, request):
        # 把对话内容拼成字符串算MD5
        content = request.meta.get("dialog", "")
        if not content:
            return False
        sig = hashlib.md5(content.encode()).hexdigest()
        if sig in self.seen:
            return True
        self.seen.add(sig)
        return False

实测能把重复句(客服常用“亲亲,在的呢”)砍掉35%,节省后续标注人力。

四、生产级考量:让爬虫7×24不掉链子

1. 分布式Redis任务队列

Scrapy-Redis官方组件即可,但生产建议再包一层优先级队列

  • 高优:人工标注过的“黄金对话”——用于few-shot采样
  • 中优:普通商品咨询页——量大管饱
  • 低优:售后纠纷——敏感词多,需二次清洗

Redis里用zadd带score,爬虫节点zpopmin取任务,保证高优先跑完。

2. 反爬触发后的自动降级

RetryMiddleware里加逻辑:

if response.status == 302 and "checkpoint" in response.url:
    # 遇到验证码跳转
    spider.logger.warning("触发验证码,自动降级")
    os.environ["SCRAPY_DELAY_MIN"] = "5"
    os.environ["SCRAPY_DELAY_MAX"] = "10"
    # 同时把代理池切换为“高匿慢速”通道
    spider.settings.set("PROXY_POOL", "slow")
    raise IgnoreRequest("进入慢速模式")

实测可以把封IP率从12%压到2%以下。

3. GDPR合规检查点

虽然国内商城,但架不住海外用户。每段对话入库前跑下面三步:

  1. 正则剔除邮箱、手机号、13位物流单号
  2. 用开源名单过滤用户名(如ZhangSan2010→**)
  3. 写Kafka时打data_type=dialog标签,下游数据湖按GDPR策略设置30天自动过期

五、避坑指南:把暗雷提前刨出来

1. 验证码破解方案对比

方案 成本 成功率 备注
打码平台(如超级鹰) 1.5元/千次 88% 适合突发,记得充值上限,防止被薅
机器学习(CNN+Resample) 训练2天+GPU 94% 长期量大才划算,模型要常迭代
人工标注外包 0.2元/张 100% 最贵,只用在黄金数据

经验:把验证码出现比例压到<1%才是正道,别一上来就硬刚。

2. 代理IP质量检测

很多代理商给你“200元/万IP”看着香,实际一半被封。跑这段脚本先验货:

import asyncio, aiohttp, time

async def check(ip):
    url = "https://httpbin.org/ip"
    try:
        async with aiohttp.ClientSession() as s:
            async with s.get(url, proxy=f"http://{ip}", timeout=5) as r:
                if r.status == 200:
                    return True
    except:
        pass
    return False

async def main():
    with open("proxy_list.txt") as f:
        ips = [l.strip() for l in f if l.strip()]
    ok = 0
    for ip in ips:
        if await check(ip):
            ok += 1
    print(f"可用率:{ok/len(ips):.1%}")

if __name__ == "__main__":
    asyncio.run(main())

可用率<70%直接找商务退钱或换包,别心疼。

六、延伸思考:采完数据怎么喂给NLP?

数据进湖后,别急着让算法同学“裸训”,先跑一轮指令微调

  1. 用ChatGLM3-6B做Teacher,对话做Student,蒸馏出领域模型
  2. 把“商品咨询→下单→售后”三段对话拼成多轮样本,加<SYS>标签提示角色
  3. 混合通用语料(如BELLE)防止灾难性遗忘

实测F1提升4.7pp,客服召回率从81%拉到89%,产品经理终于露出姨母笑。

七、一键上车:仓库与运行命令

完整代码&Docker-Compose已开源(示例地址):

https://github.com/yourname/mall-chat-dataset-spider

克隆后三步启动:

cp .env.example .env          # 改代理密钥
docker-compose up -d          # 起Redis+Kafka+Spider

打开http://localhost:6800就能看到Scrapyyd Web,点一下“Schedule”开始采,祝各位爬得开心、训得顺手。


结尾小感慨

做这整套下来,最大的感受是:AI辅助开发不只是“写代码更快”,而是把重复、脏活、体力活全部自动化,让人专注在数据质量与模型创新上。希望这篇笔记能帮你少踩几个坑,早点把智能客服练成“高情商”打工人。如果实践中遇到怪坑,欢迎来GitHub提Issue一起折腾。

限时福利领取


Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐