简介:这是一套面向电商运营人员、市场分析师及Python初学者的价格监测与分析实践方案,聚焦京东平台商品价格动态追踪与竞品对比分析。系统基于requests+BeautifulSoup实现轻量级爬虫,支持定时抓取指定商品链接的实时价格、促销信息等字段,并存入SQLite本地数据库;配套提供数据清洗、趋势统计、多商品价格对比可视化(matplotlib/seaborn)等完整分析流程。资源包共6个文件,含3个核心Python脚本(爬取、解析、主控)、1份README.md说明文档、1个说明文本及1份附赠Word版操作指南,总计36KB,结构紧凑、即拿即用。已有76人学习下载,读者可直接复用代码框架进行商品监控部署,快速掌握电商数据采集—存储—分析闭环技能,并获得可扩展的竞品价格波动研判思路。
1. 项目概述与核心价值
最近在帮一个做电商运营的朋友处理一个需求,他们想实时监控几个核心竞品在京东上的价格变动,同时分析自家产品的定价策略是否合理。手动去查不仅效率低,而且很难捕捉到那些短期的促销和秒杀价格。于是,我花了点时间,用Python搭建了一套自动化的京东商品价格数据爬取与分析系统。这套系统说白了,就是一个能定时干活、自动存数据、还能生成直观图表的“数字助理”。
它的核心工作流程很清晰:系统会按照你设定的时间(比如每小时一次),自动去访问指定的京东商品页面,把当前的价格、促销信息、商品标题等关键数据“抓”下来,然后规规矩矩地存到本地的数据库里。数据积累一段时间后,你就可以通过它内置的数据可视化功能,一眼看出某个商品的价格是“过山车”还是“一条直线”,也能轻松对比不同竞品之间的价格差异。对于做电商运营、市场研究或者单纯想“抄底”买某个东西的朋友来说,这玩意儿能省下大量机械劳动的时间,把精力聚焦在分析决策上。
整个系统的技术栈非常“亲民”,核心就是Python。用requests或selenium来模拟浏览器请求抓取网页,用BeautifulSoup或lxml解析HTML提取数据,用sqlite3或pymysql把数据存起来,最后用matplotlib或pyecharts画图分析。即使你不是专业程序员,跟着步骤一步步来,也能把它跑起来。下面,我就把这套系统的设计思路、关键代码、踩过的坑以及怎么用得顺手,毫无保留地分享出来。
2. 系统整体设计与技术选型考量
2.1 为什么选择Python与这套技术组合?
选择Python作为主力语言几乎是必然的。在数据抓取和处理这个领域,Python的生态就像个百宝箱,要什么有什么。requests库简单易用,几行代码就能完成HTTP请求;解析库BeautifulSoup和lxml对新手和老手都友好;数据处理有pandas坐镇;画图有matplotlib,seaborn,plotly等一堆选择。这种从抓取到分析无缝衔接的能力,是其他语言很难比拟的。
对于京东这种大型电商网站,我的技术选型主要基于以下几点考量:
爬虫框架:初期我直接用了
requests+BeautifulSoup的组合。它的好处是轻量、直接,学习成本低。但京东页面动态内容较多,特别是价格信息,有时通过简单的GET请求无法获取到(数据可能通过JavaScript异步加载)。这时,就需要用到selenium这类自动化测试工具来模拟真实浏览器行为,确保能抓到渲染后的完整数据。我的策略是,先用requests试,如果抓不到关键数据,再降级使用selenium。数据存储:考虑到这个系统是个人或小团队使用,对高并发要求不高,但需要轻便、易部署。SQLite成了首选。它是一个文件数据库,无需安装任何服务器,Python原生支持,非常适合本地存储和快速原型开发。如果未来数据量剧增或需要多人协作,可以无缝迁移到MySQL或PostgreSQL。
任务调度:要实现定时抓取,有两种主流思路。一是用操作系统的定时任务(如Linux的
cron或Windows的“任务计划程序”),直接定时执行Python脚本。这种方式简单粗暴,依赖系统环境。另一种是在Python脚本内部实现定时循环,比如使用schedule或APScheduler库。我选择了后者,因为这样能让整个系统更加内聚,所有逻辑都封装在一个或几个Python文件中,部署和移植更方便。可视化分析:
matplotlib是基础,功能强大但默认样式较丑。seaborn基于matplotlib,统计图表更美观。如果想做交互式图表,pyecharts或plotly是很好的选择。我最终采用了matplotlib+seaborn的组合,因为我们的分析主要是看趋势和对比,静态图表足够清晰,且对运行环境依赖最小。
注意:在技术选型上,永远要考虑“性价比”。不要一开始就追求大而全的架构。用最简单的工具解决核心问题,等需求明确、遇到瓶颈时再升级,这是最稳妥高效的开发路径。
2.2 系统架构与核心模块拆解
我把整个系统抽象为四个核心模块,它们像流水线一样协同工作:
爬虫调度模块:这是系统的大脑。它负责管理一个任务列表,列表里记录着所有需要监控的商品链接。然后,它根据预设的时间规则(例如,每天上午10点和下午4点),触发爬虫模块去工作。我使用
APScheduler库来实现这个功能,因为它支持复杂的定时规则(如每周特定几天),而且稳定可靠。数据抓取与解析模块:这是系统的“手”和“眼睛”。它接收一个商品链接,负责与京东服务器通信,下载网页内容,并从复杂的HTML代码中,精准地“抠”出我们需要的价格、商品名等信息。这是技术挑战最大的一部分,因为京东的反爬机制会不断更新。
数据存储模块:这是系统的“笔记本”。它把抓取到的结构化数据,持久化地保存到SQLite数据库中。设计一个好的数据库表结构至关重要,它决定了后续数据分析的便利性。
数据分析与可视化模块:这是系统的“嘴巴”。它从数据库中查询历史数据,通过计算和绘图,把冷冰冰的数字变成直观的折线图、柱状图,告诉我们价格是怎么波动的,谁比谁贵了多少。
这个架构清晰且解耦。每个模块各司其职,通过清晰的接口(函数调用、数据库表)连接。这意味着,如果你想更换某个部分(比如把SQLite换成MySQL,或者把matplotlib换成pyecharts),只需要修改对应的模块,而不会牵一发而动全身。
3. 核心细节解析与实操要点
3.1 京东页面分析与反爬策略应对
京东的商品页面结构比较复杂,而且反爬措施做得不错。直接requests.get()拿到的HTML,很可能找不到价格信息。价格往往藏在<script>标签的JSON数据里,或者通过接口异步加载。
第一步:定位价格数据源
打开一个京东商品页(例如某个手机),按F12打开开发者工具。
- 在
Elements标签页直接搜索“jdPrice”或“price”等关键词,可能一无所获。 - 切换到
Network标签页,刷新页面,在所有的网络请求中筛选XHR或JS类型的请求。 - 仔细观察请求的URL和响应内容。你很有可能会发现一个包含
skuId(商品ID)的接口,其返回的数据是清晰的JSON格式,里面就包含了price(价格)、name(名称)等信息。这个接口才是我们真正的目标。
例如,你可能找到类似这样的请求:https://item.jd.com/100123456789.html的真实数据来自https://p.3.cn/prices/mgets?skuIds=J_100123456789。
第二步:模拟请求头
即使找到了接口,直接访问也可能被拒绝。服务器会检查请求的Headers,特别是User-Agent。我们需要让我们的Python脚本看起来像一个真实的浏览器。
import requests headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 'Referer': 'https://item.jd.com/', # 增加Referer,更模拟真实浏览行为 } response = requests.get(api_url, headers=headers)第三步:处理动态加载与降级方案
如果上述接口方式失效,或者你需要抓取的信息必须页面完全渲染才能获得(比如“秒杀价”标签),就需要动用selenium。
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 使用无头模式,不弹出浏览器窗口 options = webdriver.ChromeOptions() options.add_argument('--headless') driver = webdriver.Chrome(options=options) try: driver.get(product_url) # 等待价格元素加载出来 price_element = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CSS_SELECTOR, "span.price")) ) price = price_element.text finally: driver.quit()实操心得:优先尝试寻找并调用数据接口,这比渲染整个页面效率高成百上千倍,对目标网站也更友好。将
selenium作为保底方案。在实际代码中,我会先尝试用requests抓接口,如果失败或数据不完整,再自动切换到selenium模式,并记录日志,方便后续排查。
3.2 数据库表结构设计
数据库设计的目标是:清晰记录每一次抓取的数据,并方便后续按商品、按时间进行查询分析。
我设计了一张核心表product_price:
| 字段名 | 数据类型 | 说明 |
|---|---|---|
id | INTEGER PRIMARY KEY | 自增主键 |
sku_id | VARCHAR(20) NOT NULL | 商品唯一ID(如100123456789) |
product_name | TEXT | 商品名称(可选,可从首次抓取或另表获取) |
price | DECIMAL(10, 2) NOT NULL | 价格(单位:元) |
promotion_info | TEXT | 促销信息(如“满减”、“秒杀”) |
capture_time | DATETIME NOT NULL | 抓取时间(精确到秒) |
source_url | TEXT | 商品页面URL |
设计理由:
sku_id是商品的唯一标识,比URL更稳定(URL可能变化)。所有分析都将围绕sku_id进行。capture_time记录抓取时刻,这是分析价格趋势的X轴。price字段使用DECIMAL类型,精确存储金额,避免浮点数精度问题。promotion_info字段存储文本,可以记录当时的活动状态,便于分析促销对价格的影响。
创建表的SQL语句如下:
CREATE TABLE IF NOT EXISTS product_price ( id INTEGER PRIMARY KEY AUTOINCREMENT, sku_id VARCHAR(20) NOT NULL, product_name TEXT, price DECIMAL(10, 2) NOT NULL, promotion_info TEXT, capture_time DATETIME NOT NULL, source_url TEXT ); -- 创建索引以加速按商品和时间的查询 CREATE INDEX idx_sku_time ON product_price (sku_id, capture_time);4. 实操过程与核心环节实现
4.1 爬虫调度器的实现
我选择APScheduler作为调度核心,因为它功能强大且易于集成到Python应用中。
from apscheduler.schedulers.blocking import BlockingScheduler import datetime from your_spider_module import main_spider_function # 导入你的抓取主函数 def job(): """定时执行的任务""" print(f"{datetime.datetime.now()} 开始执行爬虫任务...") try: main_spider_function() print(f"{datetime.datetime.now()} 爬虫任务执行完毕。") except Exception as e: print(f"{datetime.datetime.now()} 爬虫任务执行失败: {e}") if __name__ == '__main__': # 创建调度器 scheduler = BlockingScheduler() # 添加作业,每天上午10点和下午4点各执行一次 scheduler.add_job(job, 'cron', hour='10,16', minute='0') # 也可以使用间隔时间,例如每2小时执行一次 # scheduler.add_job(job, 'interval', hours=2) print("爬虫调度器已启动,按 Ctrl+C 退出。") try: scheduler.start() except (KeyboardInterrupt, SystemExit): print("调度器已停止。")BlockingScheduler会阻塞主线程,适合单独运行这个调度脚本。如果你的系统需要同时处理其他事情,可以考虑使用BackgroundScheduler。
4.2 数据抓取与存储的完整代码示例
下面是一个整合了requests抓取接口、异常处理、数据解析和SQLite存储的完整函数示例。
import requests import json import sqlite3 from datetime import datetime import time import re def fetch_jd_product_price(sku_id, product_url): """ 抓取京东商品价格并存入数据库 :param sku_id: 商品SKU ID :param product_url: 商品页面URL :return: 抓取到的价格信息字典,失败返回None """ # 1. 尝试从价格接口获取数据 price_api_url = f'https://p.3.cn/prices/mgets?skuIds=J_{sku_id}' headers = { 'User-Agent': 'Mozilla/5.0 ...', 'Referer': product_url, } price_info = None try: resp = requests.get(price_api_url, headers=headers, timeout=10) resp.raise_for_status() # 检查HTTP错误 data = resp.json() if data and len(data) > 0: price_info = { 'sku_id': sku_id, 'price': float(data[0].get('p', 0)), # 'p' 字段通常代表价格 'product_name': None, # 接口可能不返回名称,需要另外解析 'promotion_info': data[0].get('op', ''), # 'op'可能为促销信息 } print(f"接口获取成功: SKU {sku_id} 价格 {price_info['price']}") except (requests.RequestException, json.JSONDecodeError, KeyError) as e: print(f"价格接口请求失败 {sku_id}: {e}") # 此处可添加降级到selenium的逻辑 # price_info = fetch_with_selenium(product_url) # 2. 如果接口成功,尝试补充商品名称(从页面获取) if price_info: try: # 简单从URL的HTML中提取标题,实际应用可能需要更复杂的解析 page_resp = requests.get(product_url, headers=headers, timeout=10) # 使用正则简单匹配,生产环境建议用BeautifulSoup title_match = re.search(r'<title>(.*?)</title>', page_resp.text) if title_match: # 清理标题,移除“【行情 报价 价格 评测】-京东”等后缀 full_title = title_match.group(1) product_name = full_title.split('【')[0].strip() price_info['product_name'] = product_name except Exception as e: print(f"获取商品名称失败 {sku_id}: {e}") # 3. 数据入库 if price_info: save_to_db(price_info, product_url) else: print(f"SKU {sku_id} 价格信息抓取失败,本次跳过。") return price_info def save_to_db(price_info, source_url): """将价格信息保存到SQLite数据库""" conn = sqlite3.connect('jd_price_data.db') cursor = conn.cursor() sql = """ INSERT INTO product_price (sku_id, product_name, price, promotion_info, capture_time, source_url) VALUES (?, ?, ?, ?, ?, ?) """ capture_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') data_tuple = ( price_info['sku_id'], price_info['product_name'], price_info['price'], price_info.get('promotion_info', ''), capture_time, source_url ) try: cursor.execute(sql, data_tuple) conn.commit() print(f"数据入库成功: SKU {price_info['sku_id']} 于 {capture_time}") except sqlite3.Error as e: print(f"数据入库失败: {e}") finally: conn.close() # 主抓取函数,遍历监控列表 def main_spider_function(): # 你的监控商品列表,格式:[(sku_id, url), ...] product_list = [ ('100012345678', 'https://item.jd.com/100012345678.html'), ('100023456789', 'https://item.jd.com/100023456789.html'), # ... 更多商品 ] for sku_id, url in product_list: fetch_jd_product_price(sku_id, url) time.sleep(2) # 礼貌性延迟,避免请求过快 if __name__ == '__main__': # 单独测试抓取 main_spider_function()这段代码是一个可运行的最小核心。fetch_jd_product_price函数封装了从接口获取、解析到存储的完整流程,并包含了基本的异常处理。main_spider_function则负责遍历所有需要监控的商品。
4.3 数据可视化分析实战
数据存进去之后,才是价值开始体现的时候。我们使用pandas做数据处理,matplotlib和seaborn画图。
首先,从数据库读取数据:
import sqlite3 import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from datetime import datetime, timedelta # 设置中文字体(如果图表需要显示中文) plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei'] # 用来正常显示中文标签 plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号 def load_data_from_db(sku_id=None, days=30): """ 从数据库加载数据 :param sku_id: 指定商品SKU,为None则加载所有 :param days: 加载最近多少天的数据 :return: pandas DataFrame """ conn = sqlite3.connect('jd_price_data.db') start_date = (datetime.now() - timedelta(days=days)).strftime('%Y-%m-%d %H:%M:%S') if sku_id: query = """ SELECT sku_id, product_name, price, promotion_info, capture_time FROM product_price WHERE sku_id = ? AND capture_time >= ? ORDER BY capture_time """ df = pd.read_sql_query(query, conn, params=(sku_id, start_date)) else: query = """ SELECT sku_id, product_name, price, promotion_info, capture_time FROM product_price WHERE capture_time >= ? ORDER BY sku_id, capture_time """ df = pd.read_sql_query(query, conn, params=(start_date,)) conn.close() # 转换数据类型 df['capture_time'] = pd.to_datetime(df['capture_time']) df['price'] = pd.to_numeric(df['price']) # 如果product_name有空值,可以用sku_id填充 df['product_name'].fillna(df['sku_id'], inplace=True) return df接下来,绘制单个商品的价格趋势图:
def plot_single_product_trend(sku_id, days=30): """绘制单个商品的价格趋势图""" df = load_data_from_db(sku_id=sku_id, days=days) if df.empty: print(f"SKU {sku_id} 在最近{days}天内无数据。") return product_name = df['product_name'].iloc[0] plt.figure(figsize=(14, 7)) plt.plot(df['capture_time'], df['price'], marker='o', linestyle='-', linewidth=2, markersize=4) # 标注促销信息点 promo_df = df[df['promotion_info'].notna() & (df['promotion_info'] != '')] if not promo_df.empty: plt.scatter(promo_df['capture_time'], promo_df['price'], color='red', s=50, zorder=5, label='促销') # 为每个促销点添加简单注释 for _, row in promo_df.iterrows(): plt.annotate('促', xy=(row['capture_time'], row['price']), xytext=(0, 10), textcoords='offset points', ha='center', color='red', fontweight='bold') plt.title(f'{product_name} 近{days}天价格趋势', fontsize=16, fontweight='bold') plt.xlabel('抓取时间', fontsize=12) plt.ylabel('价格 (元)', fontsize=12) plt.grid(True, linestyle='--', alpha=0.7) plt.xticks(rotation=45) plt.legend() plt.tight_layout() # 保存图片 filename = f"price_trend_{sku_id}_{datetime.now().strftime('%Y%m%d')}.png" plt.savefig(filename, dpi=300) print(f"图表已保存为: {filename}") plt.show()最后,绘制多商品价格对比图(以最近一次抓取价格为例):
def plot_multi_product_comparison(sku_list): """绘制多个商品最近一次价格的对比柱状图""" latest_prices = [] product_names = [] conn = sqlite3.connect('jd_price_data.db') cursor = conn.cursor() for sku_id in sku_list: query = """ SELECT product_name, price FROM product_price WHERE sku_id = ? ORDER BY capture_time DESC LIMIT 1 """ cursor.execute(query, (sku_id,)) result = cursor.fetchone() if result: product_names.append(result[0] if result[0] else sku_id) latest_prices.append(result[1]) else: product_names.append(sku_id) latest_prices.append(0) # 无数据则记为0 conn.close() if not latest_prices: print("没有找到任何商品数据。") return plt.figure(figsize=(12, 6)) bars = plt.bar(product_names, latest_prices, color=sns.color_palette("husl", len(sku_list))) # 在柱子上方显示价格数值 for bar, price in zip(bars, latest_prices): height = bar.get_height() plt.text(bar.get_x() + bar.get_width()/2., height + max(latest_prices)*0.01, f'¥{price:.2f}', ha='center', va='bottom', fontsize=10) plt.title('竞品价格对比(最新)', fontsize=16, fontweight='bold') plt.ylabel('价格 (元)', fontsize=12) plt.xticks(rotation=15, ha='right') plt.grid(True, axis='y', linestyle='--', alpha=0.7) plt.tight_layout() filename = f"price_comparison_{datetime.now().strftime('%Y%m%d')}.png" plt.savefig(filename, dpi=300) print(f"对比图表已保存为: {filename}") plt.show() # 使用示例 if __name__ == '__main__': # 绘制指定SKU的趋势图 plot_single_product_trend('100012345678', days=7) # 对比多个SKU skus_to_compare = ['100012345678', '100023456789', '100034567890'] plot_multi_product_comparison(skus_to_compare)通过这些图表,你可以非常直观地看到:某个商品是不是在周末降价?竞品A和B的价格差是否稳定?自己的调价策略是否立刻引起了竞争对手的反应?这些洞察,就是数据带来的直接价值。
5. 常见问题与排查技巧实录
在实际搭建和运行过程中,你肯定会遇到各种各样的问题。下面是我踩过的一些坑和解决方法,希望能帮你快速排雷。
5.1 爬虫抓不到数据或数据为空
这是最常见的问题,九成以上原因出在请求本身上。
- 检查请求头:特别是
User-Agent。有些网站会对没有User-Agent或使用Python默认User-Agent的请求直接拒绝。确保你的User-Agent是一个常见的浏览器字符串。可以尝试在代码里准备几个不同的User-Agent轮流使用。 - 验证接口地址:京东的数据接口可能会变化。定期用浏览器开发者工具(F12 -> Network)重新检查一下,你之前找到的那个价格接口是否还在,URL格式有没有变。这是最需要维护的地方。
- 处理IP限制:如果你短时间内请求过于频繁,可能会触发IP限流。症状是返回一些错误页面或验证码。
- 解决方案:在请求之间增加随机延迟(
time.sleep(random.uniform(1, 3)))。 - 如果监控商品很多,可以考虑使用代理IP池,但这对于个人或小规模应用通常不是必须的。
- 解决方案:在请求之间增加随机延迟(
- 应对动态渲染:如果
requests始终拿不到价格,而浏览器能看到,那基本确定是动态加载。这时就必须启用selenium方案。记得在selenium代码中加入“显式等待”(WebDriverWait),确保元素加载完成再抓取,而不是用固定的sleep。
5.2 数据库操作错误
- 连接被锁定:如果你在多个地方或频繁地连接/关闭数据库,可能会遇到
database is locked错误。这在SQLite中较常见。- 解决方案:确保你的数据库连接在使用后正确关闭(
conn.close())。更好的做法是使用with语句或确保异常发生时也能关闭连接。对于多线程/多进程场景,需要考虑更高级的连接管理或换用MySQL。
- 解决方案:确保你的数据库连接在使用后正确关闭(
- 重复数据:如果你的调度器配置不当,可能在极短时间内触发两次抓取,导致两条几乎相同时间的数据。
- 解决方案:这通常不是大问题,分析时按时间聚合(取平均或最新)即可。也可以在插入前做一个简单判断,如果同一商品在非常短的时间间隔内(如1分钟内)已有记录,则跳过插入。
5.3 可视化图表显示异常
- 中文乱码:这是
matplotlib的经典问题。务必在绘图前设置中文字体,如前面代码所示。你需要确保你指定的字体(如SimHei)在你的操作系统上存在。 - 时间轴过于密集:如果抓取频率很高(比如每小时一次),几天的数据点就会很多,导致X轴标签重叠。
- 解决方案:使用Pandas的
resample方法对数据进行重采样,比如将每小时数据聚合成每天的平均价格再绘图。或者,调整X轴刻度的显示密度。
import matplotlib.dates as mdates # 在plot_single_product_trend函数中,设置X轴格式 ax = plt.gca() ax.xaxis.set_major_formatter(mdates.DateFormatter('%m-%d %H:%M')) # 格式化为月-日 时:分 ax.xaxis.set_major_locator(mdates.AutoDateLocator(maxticks=10)) # 自动选择最多10个刻度 - 解决方案:使用Pandas的
- 图表布局错乱:当标签较长或图表元素较多时,可能会显示不全。
- 解决方案:养成在
plt.show()或plt.savefig()前调用plt.tight_layout()的习惯,它能自动调整子图参数,使之填充整个图像区域。
- 解决方案:养成在
5.4 系统长期运行的稳定性
- 日志记录:这是最重要的!不要只用
print。使用Python内置的logging模块,将程序运行状态、抓取成功/失败、错误信息记录到文件中。这样当系统在后台运行时,你才能知道它是否健康,出了什么问题。 - 异常处理:像网络超时、解析失败、数据库断开这类错误,一定要用
try...except捕获,并进行恰当处理(如记录日志、跳过当前商品、等待后重试),避免一个商品出错导致整个程序崩溃。 - 资源清理:如果使用了
selenium,务必在finally块中调用driver.quit()来关闭浏览器驱动,否则会残留大量Chrome进程,耗尽内存。
这套系统从搭建到稳定运行,是一个不断迭代和调整的过程。一开始可能只监控几个商品,每小时抓一次。跑顺之后,再逐步增加商品数量,优化抓取策略(比如对促销频繁的商品提高抓取频率),丰富分析维度(比如加入价格变化提醒功能)。最重要的是,它真正解决了问题,把我们从重复的体力劳动中解放了出来,让决策有了数据支撑。如果你也遇到了类似的需求,不妨就从今天分享的这个基础版本开始动手试试,遇到具体问题,欢迎随时交流。
本文还有配套的精品资源,点击获取