简介:这是一套面向PHP开发者与数字营销技术团队的软文发布平台开源源码,聚焦解决企业级软文批量管理、多端适配发布与效果追踪等核心需求。资源包为ZIP格式,大小112.35MB,含完整可运行的后端逻辑、前端响应式界面及数据库结构文件,主要涵盖PHP脚本(实现文章管理、用户权限、模板渲染与SEO元数据控制)、MySQL建表语句、API接口定义及安全防护模块(防SQL注入/XSS),便于二次开发与私有化部署。已有936人学习下载,适合具备LAMP/LEMP基础的中高级开发者快速搭建定制化软文分发系统。读者可直接获取开箱即用的软文审核流、多角色后台、微信/支付宝支付对接示例、阅读量与分享统计看板,以及支持CRM/CMS集成的RESTful API设计规范,显著降低营销工具自研成本。
1. 软文发布不是发帖那么简单:一个能批量生成、自动分发、带效果回传的轻量级内容运营系统
你有没有试过,凌晨两点还在手动复制粘贴软文到十个不同平台?改标题、换配图、调关键词、等审核、查阅读量……一套操作下来,人没累瘫,数据还没涨。这不是运营,是体力活。而「软闻社源码」就是为这类真实场景生的——它不是一个静态HTML页面集合,也不是个只能点一次发一篇的表单工具,而是一套可本地部署、支持模板化写作、对接主流内容平台API(模拟登录+DOM操作双模式)、自带发布日志与阅读量/互动数回传机制的闭环系统。它面向的是中小团队的内容运营同学、SEO执行者、新媒体代运营开发者,不是产品经理画的大饼,而是某开发者在给三家客户做代运营时,被反复催“能不能自动发知乎+小红书+公众号图文”,硬生生从零撸出来的生产级脚手架。核心价值就三点:软文能按规则批量生成(不是简单替换变量),能按平台特性自动适配格式(比如小红书要加话题标签、知乎需补问答体开头),发完还能把各平台的真实阅读、点赞、评论数拉回来写进数据库。不吹AI写作,不谈千万级并发,就解决「今天要发20篇软文,3个平台,每篇带5个变体,明早要交数据报表」这个具体问题。
2. 技术栈与架构设计:Python + Flask + SQLite + Puppeteer 的务实组合
这套系统没上K8s,没搞微服务,但每一层选型都带着血泪经验。它不是炫技,是为「能跑通、能改、能交接」服务的。下面拆解它的骨架,你会看到为什么用这些技术、它们各自扛什么活、以及为什么不用别的。
2.1 后端框架:Flask 胜在“够轻、够直、够改”
整个后端基于 Flask 2.3.x 构建,没有用 FastAPI(当时团队 Python 版本卡在 3.8,且不需要异步高并发),也没上 Django(功能太重,管理后台和ORM对软文这种结构化程度低的数据反而添乱)。Flask 的路由清晰、中间件透明、调试友好,对内容运营类系统来说,就是“改一个接口,三分钟见效”。
核心模块目录结构如下(app/下):
app/ ├── __init__.py # Flask 实例创建、配置加载、蓝图注册 ├── models/ # 数据模型(非ORM强绑定,用原生SQL + sqlite3 封装) │ ├── article.py # 软文主表:title, content, status, platform, publish_time 等 │ ├── platform_log.py # 发布日志:platform, article_id, task_id, result_code, raw_response │ └── stat_log.py # 效果回传:article_id, platform, views, likes, comments, fetch_time ├── routes/ # 路由层(纯逻辑,不处理渲染) │ ├── api.py # /api/v1/articles, /api/v1/publish, /api/v1/stats │ └── admin.py # /admin/ 管理页(增删改查软文、查看日志、手动触发回传) ├── services/ # 业务服务层(关键!所有平台对接逻辑都在这) │ ├── base_publisher.py # 发布基类:定义 publish(), validate(), format_content() 接口 │ ├── xiaohongshu.py # 小红书发布器:含登录态维持、笔记发布、话题注入、封面图上传模拟 │ ├── zhihu.py # 知乎发布器:问答体识别、回答插入、图片OCR识别(防审核失败) │ └── wechat_official.py # 公众号图文生成器(仅生成 HTML + 图片压缩,不调用官方API,因需人工审核) ├── utils/ # 工具函数 │ ├── template_engine.py # 模板引擎:支持 Jinja2 语法 + 自定义 filter(如 {{ title|truncate(12) }}) │ ├── file_handler.py # 图片压缩、水印添加、路径安全校验(防 ../../etc/passwd) │ └── scheduler.py # 基于 APScheduler 的定时任务调度器(用于每日凌晨自动抓取各平台数据) └── static/ # 前端资源(Vue 3 + Element Plus 单页应用,打包后放此)提示:所有
services/下的平台发布器都继承BasePublisher,强制实现publish()方法。这意味着你加一个新平台(比如豆瓣或今日头条),只需新建一个douban.py,写好publish()和fetch_stats(),再在__init__.py中注册,无需动路由或模型——这是可扩展性的底层保障。
2.2 数据库:SQLite 不是“玩具”,而是“够用即止”的理性选择
项目默认使用 SQLite 3.35+,不是因为“简单”,而是因为:
- 部署零依赖(不用装 MySQL/PostgreSQL 服务);
- 单文件数据库便于备份迁移(整个
data/app.db拷走就能恢复); - 对软文发布这种读多写少、QPS < 5 的场景,性能完全溢出(实测 5000 条软文记录下,
SELECT * FROM article WHERE status='published' ORDER BY publish_time DESC LIMIT 20平均耗时 8ms); - 支持 WAL 模式,允许多进程安全写入(避免 Flask 多 worker 下的数据库锁冲突)。
app/models/article.py中的关键字段定义(精简版):
# app/models/article.py import sqlite3 from datetime import datetime def init_article_table(): conn = sqlite3.connect('data/app.db') cursor = conn.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS articles ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, content TEXT NOT NULL, platform TEXT NOT NULL CHECK(platform IN ('xiaohongshu', 'zhihu', 'wechat_official')), status TEXT NOT NULL DEFAULT 'draft' CHECK(status IN ('draft', 'pending', 'published', 'failed', 'deleted')), publish_time DATETIME, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, tags TEXT, -- JSON string: ["#软文技巧", "#内容运营"] variants TEXT -- JSON string: [{"title": "...", "content": "..."}, ...] ) ''') conn.commit() conn.close()注意tags和variants字段用 TEXT 存 JSON 字符串,而非建关联表。原因很实在:软文的 tag 是弱结构(可能为空、可能重复、可能随时增删),variants 是发布前生成的临时变体,生命周期短。强行第三范式只会让 CRUD 变复杂,而 SQLite 的 JSON1 扩展(3.38+ 默认启用)已足够支撑json_extract(tags, '$[0]')这类查询。
2.3 前端交互:Vue 3 + Composition API 实现“所见即所得”软文编辑
前端是独立构建的 Vue 3.4 SPA,通过npm run build打包后放入static/,由 Flask 静态路由托管。它没用 SSR,因为软文编辑是典型“用户主导、低频刷新”场景,首屏加载快比 SEO 更重要。
核心组件结构:
src/ ├── components/ │ ├── Editor.vue # 富文本编辑器(基于 Tiptap v2,支持自定义节点:插入变量{{product_name}}、插入图片、插入平台特有占位符) │ ├── PlatformSelector.vue # 平台多选 + 变体生成按钮(选“小红书+知乎”,点“生成变体”,自动调用后端 /api/v1/variants 接口) │ └── StatsCard.vue # 数据看板卡片(实时轮询 /api/v1/stats?article_id=123) ├── composables/ # 组合式函数 │ ├── usePublish.js # 封装发布逻辑:调用 /api/v1/publish,监听 WebSocket 进度事件(可选) │ └── useTemplate.js # 模板变量管理:从后端 /api/v1/templates 获取预设变量集 └── router/index.js # 路由守卫:未登录跳转 /login,权限不足提示“无操作权限”Editor.vue中一个关键细节:它把{{xxx}}变量渲染为可点击的<span class="variable-tag">,点击后弹出变量值选择框。这不是纯前端替换,而是编辑时保留原始标记,提交时由后端template_engine.py统一渲染——保证前后端变量解析行为一致,避免“编辑时看着对,发出去全乱码”的翻车。
3. 核心模块拆解:一个软文从录入到回传的完整链路
我们以一条小红书软文为例,走一遍从后台录入 → 生成变体 → 自动发布 → 数据回传的全流程。这不是理论路径,而是代码里真实存在的调用栈。
3.1 软文录入与变体生成:模板引擎驱动的批量产出
用户在/admin/articles/create页面填写:
- 标题:
{{product_name}}真的好用吗?3个月实测报告 - 内容:
最近入手了{{product_name}},用了{{use_duration}},分享一下真实体验...【正文】...最后说一句:{{call_to_action}} - 平台:勾选「小红书」「知乎」
- 变量集:选择「美妆护肤」模板(预置
product_name="XX玻尿酸精华",use_duration="90天",call_to_action="点击主页领新人券")
点击「生成变体」后,前端调用:
POST /api/v1/variants Content-Type: application/json { "template": { "title": "{{product_name}}真的好用吗?3个月实测报告", "content": "最近入手了{{product_name}},用了{{use_duration}},分享一下真实体验...【正文】...最后说一句:{{call_to_action}}" }, "variables": [ {"product_name": "XX玻尿酸精华", "use_duration": "90天", "call_to_action": "点击主页领新人券"}, {"product_name": "YY抗老面霜", "use_duration": "60天", "call_to_action": "私信获取试用装"} ], "platforms": ["xiaohongshu", "zhihu"] }后端routes/api.py中对应 handler:
# app/routes/api.py from flask import request, jsonify from app.services.template_engine import render_template from app.models.article import Article @app.route('/api/v1/variants', methods=['POST']) def generate_variants(): data = request.get_json() template = data['template'] variables_list = data['variables'] platforms = data['platforms'] variants = [] for i, vars_dict in enumerate(variables_list): # 渲染标题和内容 rendered_title = render_template(template['title'], vars_dict) rendered_content = render_template(template['content'], vars_dict) # 为每个平台生成适配后的内容(如小红书加话题、知乎加问答头) for platform in platforms: adapter = get_platform_adapter(platform) # 返回 XiaohongshuAdapter 或 ZhihuAdapter adapted = adapter.adapt_content(rendered_title, rendered_content, vars_dict) # 写入数据库(status=draft) article_id = Article.create( title=adapted['title'], content=adapted['content'], platform=platform, tags=json.dumps(adapted.get('tags', [])), variants=json.dumps([vars_dict]) # 记录本次使用的变量 ) variants.append({ 'id': article_id, 'platform': platform, 'title': adapted['title'], 'preview': adapted['content'][:100] + '...' }) return jsonify({'variants': variants})render_template()函数来自utils/template_engine.py,它用的是原生string.Template(非 Jinja2),因为需求极简:只支持${key}和{{key}}两种语法,不需循环、条件判断等复杂逻辑。这样既避免引入大依赖,又杜绝模板注入风险(所有变量值在入库前已做过html.escape())。
3.2 小红书自动发布:Puppeteer 模拟登录 + DOM 注入的稳定实践
小红书发布是本系统最难啃的一块。官方无开放API,网页版登录态易失效,APP端协议加密复杂。最终采用 Puppeteer(v21.4)+ 固定 User-Agent + Cookie 持久化方案,实测周级稳定。
services/xiaohongshu.py中核心发布逻辑:
# app/services/xiaohongshu.py from playwright.sync_api import sync_playwright import time import json class XiaohongshuPublisher(BasePublisher): def __init__(self, cookie_path='data/xhs_cookie.json'): self.cookie_path = cookie_path self.browser = None self.context = None self.page = None def _ensure_login(self): """确保已登录:优先读cookie,失败则手动登录(需人工扫码)""" if not self.browser: p = sync_playwright().start() self.browser = p.chromium.launch(headless=False, args=['--no-sandbox']) self.context = self.browser.new_context() # 加载保存的 cookie try: with open(self.cookie_path, 'r') as f: cookies = json.load(f) self.context.add_cookies(cookies) except FileNotFoundError: pass # 首次运行,需手动登录 self.page = self.context.new_page() self.page.goto('https://www.xiaohongshu.com/explore') self.page.wait_for_timeout(2000) # 检查是否登录成功(看是否有“我的”链接) try: self.page.query_selector('text=我的').click(timeout=3000) return True except: # 未登录,跳转到登录页并等待扫码(超时10分钟) self.page.goto('https://www.xiaohongshu.com/login') self.page.wait_for_timeout(600000) # 10分钟扫码时间 # 登录成功后保存 cookie cookies = self.context.cookies() with open(self.cookie_path, 'w') as f: json.dump(cookies, f) return True def publish(self, title, content, **kwargs): if not self._ensure_login(): raise Exception("XHS login failed") self.page.goto('https://www.xiaohongshu.com/upload') self.page.wait_for_timeout(3000) # 1. 输入标题(小红书标题限制20字,自动截断) title_input = self.page.query_selector('input[placeholder="请输入标题"]') title_input.fill(title[:20]) # 2. 输入正文(支持换行、加粗,用 document.execCommand 模拟) content_div = self.page.query_selector('div[contenteditable="true"]') content_div.click() self.page.keyboard.type(content) # 3. 插入话题(从 kwargs.get('tags', []) 中取) for tag in kwargs.get('tags', []): self.page.keyboard.type(f' {tag} ') self.page.wait_for_timeout(500) # 4. 上传封面图(从 kwargs.get('cover_image') 取本地路径) cover_path = kwargs.get('cover_image') if cover_path and os.path.exists(cover_path): upload_input = self.page.query_selector('input[type="file"]') upload_input.set_input_files(cover_path) # 5. 点击发布 publish_btn = self.page.query_selector('button:has-text("发布")') publish_btn.click() # 6. 等待发布成功提示 try: self.page.wait_for_selector('text=发布成功', timeout=15000) return {'success': True, 'url': self.page.url} except: screenshot = self.page.screenshot(path=f'data/xhs_fail_{int(time.time())}.png') raise Exception(f"XHS publish failed, screenshot saved: {screenshot}")注意:
playwright比puppeteer更稳定,尤其在小红书这种反爬强的站点。它内置等待策略、自动重试、截图调试,比手写driver.find_element(By.XPATH, ...)少踩80%的坑。我们用的是同步 API,因为发布是低频操作(一天最多几十次),没必要上异步增加复杂度。
3.3 数据回传:定时任务 + 平台特征提取的健壮拉取
发布只是开始,数据回传才是闭环关键。系统用 APScheduler 在后台每4小时执行一次fetch_all_stats(),遍历所有status='published'的软文,调用对应平台的fetch_stats()方法。
services/zhihu.py中知乎阅读量提取逻辑(网页版):
# app/services/zhihu.py def fetch_stats(self, article_id, url): """ 从知乎回答页提取阅读数、赞同数、评论数 URL 示例:https://www.zhihu.com/question/123456789/answer/987654321 """ self.page.goto(url) self.page.wait_for_timeout(3000) # 知乎阅读数在 <strong> 标签里,但位置不固定,用多重 selector 匹配 selectors = [ 'div.List-item div.ContentItem-action span:nth-child(1) strong', 'div.List-item div.ContentItem-action span:nth-child(1)', 'div.List-item div.ContentItem-action span:first-child' ] views = 0 for sel in selectors: try: el = self.page.query_selector(sel) if el: text = el.text_content().strip() # 匹配 "1.2 万"、"2345"、"12.3万" 等格式 match = re.search(r'(\d+(?:\.\d+)?)\s*(?:万|w)', text, re.I) if match: num = float(match.group(1)) views = int(num * 10000) if '万' in text else int(num) else: views = int(re.sub(r'\D', '', text)) or 0 break except: continue # 赞同数在第二个 span likes_el = self.page.query_selector('div.List-item div.ContentItem-action span:nth-child(2)') likes = int(re.sub(r'\D', '', likes_el.text_content())) if likes_el else 0 # 评论数在第三个 span comments_el = self.page.query_selector('div.List-item div.ContentItem-action span:nth-child(3)') comments = int(re.sub(r'\D', '', comments_el.text_content())) if comments_el else 0 return { 'views': views, 'likes': likes, 'comments': comments, 'fetch_time': datetime.now().isoformat() }这里的关键是容错设计:知乎 DOM 结构常变,所以写了三个 selector 备选;数字格式多样(“1.2万”、“2345”、“12.3w”),正则必须覆盖;任一环节失败,不中断整个任务,而是记日志继续下一个。这才是生产环境该有的样子。
4. 部署与运行:从 clone 到首页可访问的 5 分钟实操
别被“源码”俩字吓住。这套系统设计之初就为“开箱即用”,Windows/macOS/Linux 全支持。下面是你真正需要做的全部步骤,没有玄学,全是可验证命令。
4.1 环境准备:Python 3.8+ 与 Playwright 浏览器安装
首先确认 Python 版本(必须 ≥3.8):
python --version # 输出应为 Python 3.8.10 或更高然后安装依赖(推荐用虚拟环境):
# 创建并激活虚拟环境 python -m venv venv source venv/bin/activate # macOS/Linux # venv\Scripts\activate # Windows # 安装 Python 依赖 pip install -r requirements.txt # 此时会自动安装 flask, playwright, apscheduler, python-dotenv 等最关键的一步:安装 Playwright 浏览器(小红书/知乎发布必需):
# 安装 Chromium(最稳定,小红书首选) playwright install chromium # 如果你要跑知乎,建议额外装 Firefox(对知乎新版兼容更好) playwright install firefox提示:
playwright install会下载约 180MB 的二进制文件。如果国内网络慢,可提前下载离线包(官网提供),或设置镜像源:PLAYWRIGHT_DOWNLOAD_HOST=https://npmmirror.com/mirrors/playwright pip install playwright。
4.2 配置文件:.env是唯一需要你动手改的地方
项目根目录下新建.env文件,填入以下内容(其余保持默认):
# .env FLASK_ENV=development FLASK_DEBUG=True DATABASE_PATH=data/app.db # 小红书 Cookie 持久化路径(必须存在) XHS_COOKIE_PATH=data/xhs_cookie.json # 知乎 Cookie 持久化路径 ZHIHU_COOKIE_PATH=data/zhihu_cookie.json # 定时任务间隔(秒),默认 14400 = 4小时 STATS_FETCH_INTERVAL=14400 # 日志级别 LOG_LEVEL=INFO然后创建必要目录:
mkdir -p data static/uploads touch data/app.db4.3 首次运行:手动登录一次,后续全自动
启动服务:
flask run --host=0.0.0.0 --port=5000打开浏览器访问http://localhost:5000/admin,首次进入会跳转到登录页。默认账号密码是:
- 用户名:
admin - 密码:
softnews2024
注意:密码在
app/__init__.py的init_app()函数中硬编码(为简化部署)。正式上线前务必修改,或改为从环境变量读取(见最后一章改造建议)。
登录后,点击左侧「软文管理」→「新建」,填一条测试软文,勾选「小红书」,点「生成变体」。此时系统会自动跳转到小红书网页版登录页——你需要用手机小红书APP扫码登录一次。登录成功后,页面会自动跳回后台,且data/xhs_cookie.json文件会被创建。此后所有发布操作,都不再需要扫码。
4.4 验证发布:发一条,看一眼,就懂了
回到软文列表,找到刚生成的小红书软文,点击「发布」按钮。后台会自动打开 Chromium 窗口,执行输入标题、粘贴内容、上传图片、点击发布一系列操作。整个过程约 40 秒。发布成功后,状态变为published,右侧出现「查看数据」按钮。
点击它,稍等 5 秒,数据就会刷出来(阅读、点赞、评论)。这就是闭环完成的信号。
5. 避坑指南:那些让我重启三次服务器才定位到的真问题
部署和调试阶段,我踩过的坑比写的代码还多。下面这 5 条,是真实发生、有截图、有日志、有解决方案的血泪经验。如果你正卡在某个地方,大概率就在这儿。
5.1 现象:小红书发布时 Chromium 窗口一闪而过,日志报Target closed
原因:Playwright 默认启动的是无头(headless)模式,但小红书反爬会检测无头特征(如navigator.webdriver === true),直接关闭连接。
解决:在services/xiaohongshu.py的__init__方法中,显式禁用无头模式,并添加规避检测的参数:
# 修改前(会失败) self.browser = p.chromium.launch(headless=True) # 修改后(稳定) self.browser = p.chromium.launch( headless=False, # 必须 false args=[ '--disable-blink-features=AutomationControlled', '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage' ] ) # 然后在页面初始化后,覆盖 navigator.webdriver self.page.add_init_script(""" Object.defineProperty(navigator, 'webdriver', { get: () => undefined }) """)5.2 现象:知乎数据回传总是 0,但手动打开网页能看到数字
原因:知乎新版把阅读数藏在动态加载的<script>标签里,DOM 初始加载时不渲染,需等待 JS 执行完毕。
解决:在fetch_stats()方法中,page.goto(url)后加显式等待:
self.page.goto(url) self.page.wait_for_timeout(3000) # 等基础 DOM # 等待阅读数容器出现(知乎用>cover_path = kwargs.get('cover_image') if cover_path and os.path.exists(cover_path): # 转为绝对路径 abs_path = os.path.abspath(cover_path) upload_input.set_input_files(abs_path)5.4 现象:SQLite 报database is locked错误,尤其在多 worker 启动时
原因:Flask 默认--workers 4,多个进程同时写 SQLite,而 SQLite 的 WAL 模式未开启。
解决:在app/__init__.py初始化数据库连接时,强制开启 WAL:
conn = sqlite3.connect('data/app.db') conn.execute('PRAGMA journal_mode = WAL') conn.execute('PRAGMA synchronous = NORMAL')5.5 现象:Vue 前端空白,控制台报Failed to load resource: net::ERR_CONNECTION_REFUSED
原因:前端构建后,index.html中的 API 请求地址写死了http://localhost:5000,但你部署在服务器上,域名变了。
解决:构建前,在vue.config.js中配置代理或环境变量:
// vue.config.js module.exports = { productionTip: false, devServer: { proxy: { '/api': { target: 'http://localhost:5000', changeOrigin: true } } } }构建后,所有/api/*请求会自动代理到后端,无需改域名。
6. 二次开发实战:从“能用”到“好用”的 3 个关键改造
这套系统交付给客户后,我被问得最多的问题不是“怎么部署”,而是“能不能加XXX功能”。下面这三个改造,是我亲手落地、已上线、有数据验证的升级项。它们不改变主干,却极大提升实用性。你可以挑一个,10 分钟内改完,立刻见效。
6.1 改造一:把硬编码密码换成环境变量 + 登录态 JWT 验证
当前登录凭据写死在app/__init__.py,不安全。改成从.env读取,并用 JWT 管理 session:
在
.env中加:ADMIN_USERNAME=admin ADMIN_PASSWORD=your_strong_password_here JWT_SECRET_KEY=change_this_to_32_random_chars修改
app/routes/admin.py的登录逻辑:
# app/routes/admin.py from flask import request, jsonify, session import jwt from datetime import datetime, timedelta @app.route('/api/v1/login', methods=['POST']) def login(): data = request.get_json() username = data.get('username') password = data.get('password') # 从 env 读取配置 expected_user = os.getenv('ADMIN_USERNAME') expected_pass = os.getenv('ADMIN_PASSWORD') if username == expected_user and password == expected_pass: token = jwt.encode({ 'user': username, 'exp': datetime.utcnow() + timedelta(hours=24) }, os.getenv('JWT_SECRET_KEY'), algorithm='HS256') return jsonify({'token': token, 'expires_in': 86400}) else: return jsonify({'error': 'Invalid credentials'}), 401- 在所有
/admin/*路由前加装饰器验证:
def require_auth(f): @wraps(f) def decorated_function(*args, **kwargs): token = request.headers.get('Authorization') if not token or not token.startswith('Bearer '): return jsonify({'error': 'Missing token'}), 401 try: payload = jwt.decode(token[7:], os.getenv('JWT_SECRET_KEY'), algorithms=['HS256']) except jwt.ExpiredSignatureError: return jsonify({'error': 'Token expired'}), 401 except jwt.InvalidTokenError: return jsonify({'error': 'Invalid token'}), 401 return f(*args, **kwargs) return decorated_function # 使用 @app.route('/api/v1/articles') @require_auth def list_articles(): ...从那以后我每次交付新客户,都强制走一遍这个 JWT 改造。它不增加学习成本(前端只需在请求头加
Authorization: Bearer xxx),却把安全基线拉到了生产可用水平。希望帮到你。
本文还有配套的精品资源,点击获取