资讯详情 电商数据自动抽取与NLP营销文案生成流水线搭建指南
📅 2026/10/12 13:25:08
简介一套基于Python实现的电商数据自动抽取营销文案项目源自京东NLP高阶实战训练营二期。项目利用京东商品标题、属性标签与OCR信息通过seq2seq、注意力机制和指针网络等模型自动生成营销文案完整覆盖数据预处理、特征工程、模型训练与评估环节适合NLP方向学生、算法工程师及用于毕业设计或课程设计。压缩包共63个文件大小21.78MB以27个Python源码文件为主辅以编译文件、TXT配置说明、PNG结构图、XML工程配置和Markdown项目文档另含处理好的服饰50K数据集、配置文件与工具模块目录层次清晰便于定位和二次开发。代码均在上传前测试运行成功作为毕设项目评审平均分达96分已有157人学习下载附有问题记录和README说明能够帮助读者理解模型设计、复现实验并拓展应用。整体工程逻辑清晰适合作为实战入门与进阶参考。1. 电商文案自动化从商品数据到营销文案这条流水线到底怎么搭做过电商运营或外包代运营的人都体会过写商品文案的苦一个新品上架要标题、卖点、详情页话术、推广短文案一个店铺几十上百个SKU靠人工写到手软而且写得慢、风格还不统一。这个项目标题里提到的“电商数据自动抽取 NLP 营销文案生成”就是把这套流程自动化先用Python把商品页里的标题、价格、规格、卖点等字段抽成结构化数据再用NLP技术把这些字段组合成可读、有说服力的营销文案。它解决的痛点是「批量」和「一致性」适合已经有Python基础、想找一个NLP落地场景的从业者也适合电商团队里负责商品运营的工程师。这套方案不依赖大模型推理服务普通机器就能跑成本可控值得照着搭一遍。2. 电商数据自动抽取先把商品页拆成“文案原料”营销文案不是凭空写出来的它依赖商品本身的属性、价格、促销信息、用户评价这些原始数据。所以整条流水线的第一步是抽取。2.1 先拆字段一份营销文案需要哪些“原料”写文案之前我会先列一张字段清单不是看到页面有什么就抓什么而是反过来想——最终文案里要出现哪些信息我就抓哪些。以京东这类电商平台为例一份能自动生成营销文案的商品数据至少要包含这几类字段基础身份类商品标题、品牌、三级类目、SKU规格颜色、容量、版本。价格促销类当前售价、划线价京东叫京东价与市场价、促销标签满减、赠品、PLUS专享。卖点类主图下方的服务承诺放心购、极速退款、规格参数表里的关键参数续航、功率、材质。社会证明类好评率、评价数量、精选评价里的高频词。很多新人做抽取时习惯把整个页面HTML下载下来然后开始找XPath。我建议反过来先把目标文案的模板草稿写出来比如“【品牌】【商品名】【核心卖点】限时到手价【价格】”再对照模板去补字段。这样做的好处是抽取阶段就知道哪些字段是必须的不会在解析时陷入“把整个页面都存下来”的冲动。字段定好后下一步是确定数据来源页。商品详情页通常包含标题、价格、规格参数列表页包含多个商品的基础信息评价页则包含用户评论。常见做法是爬详情页为主列表页只用来拿商品ID集合。注意平台数据属于商家和平台资产个人学习和研究用少量数据没问题但如果要商用务必走官方开放平台或授权渠道别为了跑通流程把自己放到合规风险里。2.2 用 requests parsel 把商品页拆成结构化数据抽取环节最常见的实现方案是 requests 拿 HTML再用 parsel 或 lxml 做解析简单直接也方便后续调试。我不建议一上来就上 Scrapy流程没跑通之前Scrapy 的中间件、管道这些概念会干扰你对解析逻辑的思考。先用一个脚本把单页跑通再考虑工程化。import requests import json from parsel import Selector HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Referer: https://www.jd.com/, } def fetch_item(item_id: str) - dict: # 商品详情页是半静态页面标题和规格参数通常直接渲染在HTML里 url fhttps://item.jd.com/{item_id}.html resp requests.get(url, headersHEADERS, timeout10) resp.encoding utf-8 sel Selector(textresp.text) title sel.css(div.sku-name::text).get().strip() brand sel.css(#parameter-brand li::text).get().replace(品牌, ).strip() # 规格参数在“商品介绍”下方的参数面板里逐行解析 params {} for li in sel.css(#detail .parameter2 li): text li.css(::text).get().strip() if in text: k, v text.split(, 1) params[k.strip()] v.strip() return { item_id: item_id, title: title, brand: brand, params: params, } if __name__ __main__: data fetch_item(100012043978) print(json.dumps(data, ensure_asciiFalse, indent2))这段代码做了几件事带 Referer 和 User-Agent 发起请求避免最简单的反爬拦截用 CSS 选择器定位标题和品牌用split(, 1)按中文冒号拆分规格参数。要注意:text拿到的列表get()在没匹配到时会返回空字符串保证字段缺失时不抛异常。参数里最重要的一项是resp.encoding utf-8漏掉它的话京东页面返回的中文可能乱码这是高频翻车点。跑通单个商品后就要处理商品ID集合。常见做法是先从搜索列表页或分类页拿ID再逐个请求详情页。列表页URL里通常能直接看到关键词或类目ID解析方式类似只是把div.sku-name换成列表项的选择器。还有一点要提醒解析出的字段一定要当场打印出来看很多字段选择器在改版后就失效了调试时拿真实页面比对比看教程更管用。2.3 价格和 SKU 动态渲染的处理两种常见做法详情页的标题和规格参数是静态HTML但价格不是。京东的价格接口是独立的常见做法是请求https://p.3.cn/prices/mgets?skuIdsJ_商品ID返回一个JSON数组包含当前价和原价。这个接口单独请求不跟在详情页请求后面避免每次访问详情页都多带一个价格请求。import requests import json def fetch_price(item_id: str) - dict: # 价格走独立接口返回JSON比解析HTML更稳 sku fJ_{item_id} url https://p.3.cn/prices/mgets params {skuIds: sku} resp requests.get(url, paramsparams, timeout5) resp.encoding utf-8 data resp.json()[0] return { item_id: item_id, price: data.get(p), original_price: data.get(m), }需要说明的是这个接口返回的p是当前到手价m是市场价也就是页面上的划线价。如果要做“限时特惠”类文案这两个字段是核心素材。另一个必须留意的点是 SKU 选择——有的商品有多个颜色版本J_后面跟不同的ID拿到的是不同SKU的价格所以抽取阶段要提前决定是抓默认SKU还是把全部SKU都抓下来再挑最低价。我一般会抓默认SKU因为默认SKU和详情页标题对应的规格是一致的文案里不会出现“标题写的是A款价格却是B款”的尴尬。至于平台风控个人学习场景下请求频率控制在每秒1次以内加延时问题不大。如果出现验证码或302跳转先停下来观察一下自己的请求频率和请求头而不是马上找代理。很多反爬其实是请求频率太密集触发的降低频率后自然恢复。3. NLP文案生成模板先跑通再考虑生成模型数据抽出来后就到了标题的另一个核心词NLP。很多人一想到NLP就会想到GPT这类大模型但这类模型在电商场景上有一个现实问题不可控。生成的文案很可能出现“这个商品很好”这类空话甚至幻觉出商品并不存在的参数。所以我的建议是冷启动阶段用规则模板 关键词抽取来生成文案数据量大了、有了明确的风格要求之后再上生成模型。3.1 为什么冷启动阶段用模板而不是生成模型模板生成听起来“不够NLP”但它有三个不可替代的优势可控、可解释、可批量。模板的每一段话都能追溯到某个字段比如“【品牌】【标题】”这行品牌字段抓不到文案里就会明确缺这一块不会瞎编。更重要的是电商文案有强合规要求不能乱写功效、不能编参数。生成模型写出一句“续航提升50%”可能很顺但你没处核对这句话是不是真的这就涉及虚假宣传了。模板生成从源头杜绝了这种风险。但纯模板的问题也明显同质化严重所有商品都用同一句式读起来像机器写的。所以要在模板里加入“可变卖点块”——从商品的规格参数里抽关键词匹配卖点词库命中哪个就渲染哪个句子。这样一百个商品就有一百种文案组合而不是一百遍重复同一句话。3.2 用 jieba 做标题分词抽品牌、类目、规格词先看标题里能抽到什么。电商标题的格式比较固定通常是“品牌系列核心规格商品类型服务词”例如“Apple/苹果 iPhone 15 128GB 蓝色 全网通5G手机”。用 jieba 分词后再配合自定义词典能把品牌、颜色、存储容量这类关键属性捞出来。import jieba # 因为是垂直电商领域建议把品牌、类目词加到自定义词典分词会更准 jieba.add_word(全网通, 10000) jieba.add_word(Apple, 10000) def extract_attrs(title: str) - dict: # 电商标题结构性很强先按空格粗切再做细粒度识别 tokens title.split() attrs { brand: , color: , spec: , product_type: , } # 颜色词表可以按类目扩充这里是常见电子品类目 color_words [蓝色, 黑色, 白色, 粉色, 金色, 灰色, 紫色] for token in tokens: for color in color_words: if color in token: attrs[color] color # 品牌优先匹配自定义词表没命中再用tf-idf会不准 for token in tokens: if token in Apple华为小米荣耀OPPOvivo联想戴尔: attrs[brand] token break # 规格词通常包含数字单位比如128GB、15.6英寸 for token in tokens: if any(unit in token for unit in [GB, TB, 英寸, W, mAh]): attrs[spec] token # 商品类型在标题末尾结合类目词的常见后缀判断 for token in tokens: if any(word in token for word in [手机, 电脑, 耳机, 充电器, 显示器]): attrs[product_type] token return attrs这个函数的逻辑很直白先按空格切分标题再用关键词表逐项匹配。实际项目中品牌表、颜色表、规格单位的完备度直接决定抽取质量这也是需要花最多时间维护的部分。分词之后还能用 jieba 的posseg模块分析词性但我觉得在标题这种短文本上词表匹配比词性标注更实用词表缺失的词再走词性分析兜底。这里有个参数值得说jieba.add_word的第二个参数是词频给一个足够大的数比如10000能让这个词大概率被识别为一个整体而不是被切开。比如“全网通”如果不加词典可能被切成“全网”和“通”后面做规格匹配就乱了。3.3 模板渲染把结构化字段变成一段营销文案字段抽取完成后就可以做模板渲染。我习惯把模板做成 JSON 配置文件而不是写死在 Python 代码里。这样运营同事也能自己改文案句式不用动代码。import json import random from typing import dict TEMPLATES { default: [ {brand}{product_type}{title}限时特惠仅需{price}元, {prod_title}直降好价到手只要{price}元{spec}大容量/高性能不容错过, 爆款{product_type}来袭{title}{promotions}{price}元带回家, ], promotion: [ 限时直降{title}到手价{price}元比原价{original_price}省了不少, ], } def render_copy(product: dict, promo_tag: str ) - str: # promo_tag 命中促销标签后换用对应的促销模板 template_key promotion if promo_tag else default templates TEMPLATES[template_key] title product.get(title, ) brand product.get(brand, ) or 精选 spec product.get(spec, ) price product.get(price, ??) original_price product.get(original_price, ) # 随机选一个模板避免同一批商品文案完全一致 tpl random.choice(templates) return tpl.format( brandbrand, product_typeproduct.get(product_type, 商品), prod_titletitle, specspec, priceprice, original_priceoriginal_price, promotionspromo_tag or 品质保障, )这段代码的核心是把文案模板和数据解耦。随机选模板是为了保证批量生成时文案不重复但如果你希望同一店铺风格固定可以把random.choice改成按商品类目hash取模板这样同类目永远用同一个句式跨类目有区分度。模板配置里有一个容易踩的坑占位符与字段名不一致。比如模板里写了{spec}代码里字段名却是specs跑的时候不会报错但生成文案会直接出现“None”或者空白。我一般会在渲染后加一个校验函数检查最终文案里是否还残留{}符号有就说明有字段没替换成功。3.4 什么时候该升级到 Seq2Seq 或微调模型模板跑通后你会面临一个新问题文案还是不够“活”。模板的句子结构是固定的再怎么组合跟真人运营写的还是有差距。这时才轮到生成模型上场。我的建议是分两步走。第一步先用一个轻量的抽取式方案——从用户评价里提取高频好评词拼进模板的“卖点句”。比如一个充电宝的评价里高频出现“轻薄”“充电快”就把这两个词放进“【轻薄机身】【充电快】”的句式块。这一步仍然不依赖生成模型但已经比纯静态模板更贴近用户语言。第二步如果积累了几万条“商品字段→人工文案”的成对数据再考虑微调一个 T5 或 ChatGLM 这类开源模型输入格式是 JSON 字段输出是文案。微调的目的是让模型学会电商文案的句式和卖点组织方式而不是让它自由发挥。这里想提醒一句生成模型的“智能”在电商文案场景里是双刃剑。自由生成的文案如果没人审核就发出去效果不达预期事小出现合规问题事大。所以即使上了生成模型也要保留模板兜底模型生成的文案过一遍敏感词和字段校验不过就退回模板渲染。这个策略我一直在用。4. 跑通最小系统从商品链接到文案文件的完整管道前面两章分别讲了抽取和生成这一章把它们串成一个可直接命令行运行的管道。初学者最容易在这里卡住代码单独跑都能跑一拼起来就各种路径引用错误。所以项目结构一开始就要立好。4.1 项目目录怎么组织源码和项目说明文档各管什么这份实践项目里提到的“源码 项目说明文档”落到目录上我一般这样组织jd_nlp_campaign/ ├── configs/ │ └── config.yaml # 全局配置输入输出路径、模板开关、请求频率 ├── data/ │ ├── raw/ # 抓下来的HTML或JSON原始数据 │ ├── parsed/ # 清洗后的结构化商品数据 │ └── output/ # 最终生成的营销文案文件 ├── src/ │ ├── fetcher.py # 请求详情页、价格接口 │ ├── parser.py # HTML解析输出结构化字段 │ ├── nlp_utils.py # 分词、属性抽取、卖点词匹配 │ ├── copywriter.py # 模板渲染与文案生成 │ └── pipeline.py # 串联流程命令行入口 ├── tests/ │ ├── test_parser.py │ └── test_copywriter.py └── README.md # 项目说明环境安装、运行方式、字段说明这样拆的目的很单纯任何一环出问题都能快速定位。抓下来的原始数据放在raw/解析后的放在parsed/最终文案放在output/。如果哪天发现文案质量不对可以倒回去看是解析阶段的字段丢了还是模板配置的问题。4.2 配置文件输入路径、平台字段映射、模板开关我强烈建议把可变参数全部放到配置文件里而不是散落在代码各处。下面是一份最小配置# configs/config.yaml platform: jd request: timeout: 10 interval_seconds: 1.2 # 请求间隔单位秒避免触发风控 retry_times: 3 input: item_ids_file: data/raw/item_ids.txt # 每行一个商品ID output: parsed_file: data/parsed/items.jsonl copy_file: data/output/copy.jsonl copy_encoding: utf-8 nlp: user_dict: configs/user_dict.txt # 自定义词典品牌、类目词 enable_promotion_match: true # 是否匹配促销标签 model: template # 可选template / finetunedinterval_seconds是一个值得认真对待的参数。电商平台对高频请求很敏感1秒2秒还好如果要抓几千个商品建议改成随机延时random.uniform(0.8, 1.5)不要用固定间隔固定间隔本身就是一种容易被识别的特征。model字段留了finetuned选项目前先跑template以后真微调了模型只需要改配置不用改管道代码。4.3 一键运行从商品链接到文案文件的完整管道管道入口我习惯写成pipeline.py接收配置文件路径为参数。内部流程是读商品ID列表逐个请求详情页解析字段抽取属性渲染文案最后把结构化数据和文案一起写成 JSONL。# src/pipeline.py import json import time import random import argparse import yaml from fetcher import fetch_item, fetch_price from parser import parse_item_html from nlp_utils import extract_attrs from copywriter import render_copy def load_item_ids(filepath: str) - list: # 商品ID文件每行一个ID空行和注释直接跳过 ids [] with open(filepath, r, encodingutf-8) as f: for line in f: line line.strip() if line and not line.startswith(#): ids.append(line) return ids def main(config_path: str): with open(config_path, r, encodingutf-8) as f: cfg yaml.safe_load(f) item_ids load_item_ids(cfg[input][item_ids_file]) results [] for item_id in item_ids: try: html_data fetch_item(item_id) html_data.update(fetch_price(item_id)) product parse_item_html(html_data) attrs extract_attrs(product[title]) product.update(attrs) copy_text render_copy(product, promo_tagproduct.get(promo_tag, )) product[copy] copy_text results.append(product) print(f[OK] {item_id} - {copy_text}) # 请求间隔放在每次循环末尾避免列表第一个请求没有延时 time.sleep(cfg[request][interval_seconds] * random.uniform(0.8, 1.2)) except Exception as e: print(f[FAIL] {item_id}: {e}) continue with open(cfg[output][copy_file], w, encodingutf-8) as f: for item in results: f.write(json.dumps(item, ensure_asciiFalse) \n) if __name__ __main__: parser argparse.ArgumentParser(description电商数据抽取与文案生成管道) parser.add_argument(--config, defaultconfigs/config.yaml) args parser.parse_args() main(args.config)这段代码有三个设计点值得说明。第一fetch_item返回的是 HTML 文本fetch_price返回的是 JSON 解析后的字典用update合并后统一交给parse_item_html这样解析函数只管一个输入。第二每次请求后延时用了random.uniform做扰动同时把延时放在循环末尾保证第一个请求是立即发出的调试时不会因为没有延时而干等。第三异常处理是continue而不是break一个商品挂了不应该中断整个批处理但要打印出失败的商品ID方便之后重跑。跑完这个管道后打开data/output/copy.jsonl每一行就是一个商品的完整数据加文案。你可以用 Excel 或 pandas 转成 CSV 发给运营审核。到了这一步“电商数据自动抽取 营销文案生成”的最小闭环就跑通了。5. 避坑指南这套流水线最常见的 5 个事故把项目从“能跑”到“稳定跑”中间隔着不少坑。这里有我横跳过的真问题按“现象→原因→解决”的方式给你说清楚。5.1 抓下来是乱码品牌字段全是“锟斤拷”现象打印title时中文全部变成乱码尤其是“锟斤拷”这种标志性字符。原因requests默认按响应头里的 charset 解码但部分京东页面响应头没带 charsetRequests 就会用默认的 ISO-8859-1 解码中文自然全乱。代码里resp.encoding utf-8的位置不对或者根本漏了。解决在拿到resp.text之前就设置resp.encoding utf-8。更好的做法是用resp.apparent_encoding先探测再手动确认。注意如果用了resp.json()解析价格接口JSON 接口本身是 UTF-8不用额外设置。5.2 价格接口返回空值文案里出现“到手价None”现象商品文案生成成功但价格位置出现“None”或“??”。检查日志发现fetch_price返回了空字典。原因京东价格接口的返回结构和 SKU 有效性有强关联。商品ID对应的 SKU 已下架接口返回空数组或者skuIds参数格式写错漏了J_前缀。另一个原因是你抓了多个 SKU但只用了第一个 SKU 的价格无法对上默认 SKU 显示的规格。解决在parse_item_html前加一个价格校验price字段为空直接丢弃这条商品不要让它进入文案渲染。同时把skuIds参数固定成J_ 详情页URL里的商品ID别从别的页面拼接。5.3 文案生成成功但每句都一模一样运营拒绝使用现象跑完100个商品生成的文案除了商品名不同句式、形容词、卖点句完全相同。原因模板数量太少加上render_copy里没有随机性。比如你的模板只有1个那不管怎么组合都是同一句话。另外商品字段同质化严重比如100个商品里90个的规格都是“128GB”卖点句自然雷同。解决扩充模板库到10条以上并且把“卖点块”做成可变量。用评价高频词作为卖点词按字段命中不同句式。再不够就引入商品类目维度手机类目用性能句式服饰类目用场景句式。5.4 商品ID文件里混入了换行和空格导致请求404现象批处理跑到一半大量商品请求 404 或被重定向到首页但这些商品在浏览器里能正常打开。原因load_item_ids没有清理空格或者 ID 文件里混入了 Excel 粘贴进来的不可见字符。比较隐蔽的是 BOM 头文件开头多了\ufeff第一个商品 ID 实际是\ufeff100012043978请求直接打到不存在的 URL 上。解决读取文件时用line.strip()清理同时打开文件用encodingutf-8-sig自动去掉 UTF-8 BOM。这是我反复踩过的一个坑——明明第一个 ID 看起来没问题但请求就是404排查了很久才发现是 BOM 在作怪。5.5 请求频率一高整批 IP 被风控拦截只能换网络重来现象抓了百来个商品后突然连续出现验证码和跳转登录页再请求就全被限流。原因固定间隔请求在短时间内容易被识别为脚本行为。尤其是用每秒2次的固定速率并发采集时流量特征十分明显。解决把固定延时改成随机延时并控制整体吞吐。风险控制不单看单次频率还看短时间内的总请求量所以批处理建议分段跑每段之间歇三五分钟。还有一个很少有人注意的细节不要在请求头里带多余的浏览器特征比如带了一个和实际版本对不上的Chrome/124反而更容易被规则命中。另外提一句Windows 上跑这套管道时经常遇到 JSON 输出文件打开乱码这是 Windows 记事本默认 GBK 读取导致的。写文件时用encodingutf-8-sig就能让 Excel 和记事本都正确识别这个小改动可以避免大量“文件是好的但看不出内容”的纠结。6. 进阶玩法从“批量出文案”到“文案真的能带货”模板管道跑通只是及格线真正让这套系统有价值的是后面这步把文案的“生成”和“效果”闭环起来。我的做法是给每一条生成的文案打上唯一标记比如隐藏在链接参数里的fromcopy_001发到不同渠道后统计曝光到点击的转化率。有了效果数据就按 CTR/转化率给模板排序好的模板保留差的模板回炉。这套A/B验证机制跑一个月模板库会从“拍脑袋写”变成“数据筛出来”。另一个方向是文案的个性化重写。同一件商品投放到不同渠道受众的敏感点不一样。公众号用户吃“限时直降”这类稀缺性话术小红书用户吃“颜值高”“氛围感”这类场景词。我一般会在模板里加一个channel维度同一个商品的字段按渠道选择不同的卖点顺序。这一步不增加多少代码量但对文案效果的提升很明显。如果你真想往生成模型方向走我建议把注意力放在数据管道上而不是模型本身。先跑两个月模板管道把“商品字段 - 最终上架文案 - 效果数据”这三张表攒下来再用这些数据去微调模型。你会发现训练数据质量决定文案质量而数据质量恰恰由你现在这套抽取管道的字段完整性决定。这也是我在这类项目里养成的一个习惯任何时候都先把日志和数据落盘保存因为以后微调模型时这些原始字段就是唯一值得信赖的训练语料。最后说一句我自己的教训自动化文案项目失败往往不在NLP模型而在上游数据抽取的稳定性。把抓取、解析、清洗做扎实这个项目就已经成功了八成。希望帮到你。本文还有配套的精品资源点击获取