文章目录
前言
这篇文章旨在记录我初次接触电商行业的经历,主要包括电商行业整体发展前景和趋势,以及我个人在从事电商开发时所遇到的一些独有属性和特点。
一、我了解到的传统电商现状
在我入职的第一天,公司的ITBP
(信息技术业务伙伴)与我进行了面谈,主要介绍了公司的架构,包括整个业务流程。据了解,公司正在进行业务信息化转型,计划将化学品业务转移到自研的电商平台上,同时面对竞争对手如阿里的1688
等电商平台。
我首先向ITBP
提出了为什么从阿里跳槽到这家公司的问题。ITBP
比我早两个月入职,之前在网易严选和阿里都担任相关负责人职位。他解释说,目前传统电商市场趋于饱和,大量的人员和店铺造成了公司运营成本大幅增加。未来如果找不到新的突破口进行转型,那么即使像阿里这样的企业也只能裁员来降低成本。因此,他和1688
生态运营总监一起选择跳槽到现在的公司,以致力于发展化工品电商平台。
在我们的交流中,ITBP
还简要介绍了自研电商平台的技术框架,以及目前正在研发的方向。
二、自研电商平台核心竞争力
1.优化购物体验
公司的BtoB
电商平台专注于为高校实验室和企业实验室提供化工品选购服务。针对这些拥有充足经费的单位,我们的核心业务目标是优化购物体验,从化工品的选品、购买流程、结算,再到开具发票,力求为客户打造卓越的服务体验。尤其在化工品的选购环节,提供人工选品服务,根据客户的专业需求和规格要求,推荐适用的化工品品牌,确保为客户提供最合适的选择。
此外,我们还提供高效的购物结算流程,以及快速且准确的发票开具服务,确保客户在购物过程中获得便捷和专业的支持。
除了选品优化和完善的购物流程,我们还将公司传统业务与电商平台有机融合。化工品运输和绿色回收服务将为客户提供全方位支持,确保客户在购物后的使用和废弃处理环节得到周到的关怀。通过整合各项服务,我们力求为客户打造一体化的高品质体验,使其在化工品选购过程中获得便捷、专业和可靠的支持。
2.SEO优化
在平台初期,我了解到的最重要的任务是通过增强SEO
(搜索引擎优化)来提高平台在搜索引擎中的排名,从而让潜在客户能够轻松地找到我们的平台。为了快速提升排名,公司主要采用了快速排名增强策略,即购买词条广告位,这样可以在搜索引擎结果页面中获得更显眼的位置。
在实施快速排名增强策略时,我们主要专注于以下方面:
- 选购商品的关键词选择:
进行详细的关键词研究,找到与我们的商品和服务相关的高频搜索词和长尾关键词。通过购买与这些关键词相关的词条广告位,将我们的平台展示给潜在客户。 - 百度购买词条:
利用百度推广(百度的广告平台)购买相关词条的广告位,这样当用户在搜索引擎中输入与我们关键词相关的搜索时,我们的广告就会在搜索结果中显示,提高了平台的曝光度和点击率。
快速排名是一种按关键词,按天收费 ,一般是采取预付费用方式,一个词10元左右(根据词的指数及其他因素收费),然后排名上到首页之后开始收费,这种一般上排名速度比较快,简单点的词一周内就可以上排名,这种形式快,缺点如果没做上去或者做上去之后停了,对网站后期影响比较大。
- 广告创意和优化:
制作吸引人的广告创意,强调平台的特点和优势,吸引用户点击(比如做平台的电商大屏广告)。同时,定期对广告进行优化,根据数据分析调整投放策略,提高广告效果和点击转化率。 - 监测与分析:
持续监测广告效果,收集数据并进行分析,了解广告投放的效果如何,是否吸引了目标受众。根据数据反馈做出相应调整,不断优化广告投放策略,提高ROI
(投资回报率)。
通过这样的快速排名增强策略,我们能够在初期阶段迅速提高平台在搜索引擎中的曝光度和可见性,吸引更多潜在客户,从而为公司的电商平台带来更多的流量和潜在业务机会。
3.UI设计和商详介绍
3.1UI设计:
-
简洁和直观:保持界面简洁,避免过多的视觉干扰,让用户能够快速找到需要的信息和商品。
-
色彩和品牌一致性:选择与化工行业相关的色彩和图标,保持与公司品牌一致性,增强用户对品牌的记忆。
-
导航设计:设计清晰的导航菜单,以及搜索功能,方便用户快速定位和筛选所需的化工产品。
-
产品分类和过滤:采用合理的分类和过滤功能,使用户能够便捷地找到他们感兴趣的化工商品。
3.2 商详介绍:
-
高质量的产品图片:提供清晰、高质量的产品图片,让用户能够直观地了解化工品的外观和特点。
-
详细的产品描述:提供详细的产品介绍,包括规格、用途、性能等信息,满足用户对化工品的需求了解。
-
省心的询价系统:对于化工品,提供易操作的询价接口,帮助用户做出明智的购买决策。
-
推荐和相关产品:根据用户的浏览历史和购买行为,推荐相关的化工产品,提高交叉销售机会。
-
免费样品或试用:对于某些化工品,提供免费样品或试用的机会,增加用户试用的动力和信心。
三、技术部分
1. 服务端渲染 (SSR)
在项目接手初期,我首次接触的前端框架是Nuxt.js。相较于Vue.js
,Nuxt.js
有其特有的生命周期。Nuxt.js
是一个基于Vue.js的服务端渲染应用框架,兼具Vue.js
的强大功能和服务端渲染(SSR
)的优势。
Nuxt.js
在电商平台应用的突出优势:
SEO
优化:
电商平台在竞争激烈的市场中需要出色的搜索引擎优化(SEO
)来吸引更多有针对性的访问者。Nuxt.js
s支持服务端渲染,可以提供预渲染的HTML
内容给搜索引擎爬虫,有利于搜索引擎对网站内容的抓取和索引,从而显著提高搜索引擎排名。- 快速加载:
电商平台的页面通常包含大量的商品信息和图片。借助Nuxt.js
的服务端渲染能力,可以在服务端直接渲染页面内容并将其迅速返回给用户,从而显著加快页面加载速度,极大地提高用户体验。
在我们的电商平台应用中通过充分利用Nuxt.js
的特性,我们能够有效地提升电商平台的SEO
效果,吸引潜在客户,提高网站在搜索引擎中的可见性和排名。
1.1 Nuxt.js 实现 SSR 的原理
Nuxt.js 是一个基于 Vue.js 的服务端渲染应用框架,它采用了以下原理来实现服务端渲染 (
SSR
):
- 服务器端渲染:Nuxt.js 在服务器端渲染
Vue
组件,并生成完整的HTML
页面,然后将渲染好的页面发送给客户端。这样,搜索引擎和浏览器都能够直接获取到已经渲染好的HTML
内容,有利于SEO
,同时也提高了页面的加载速度。 - 客户端激活:当客户端收到由服务器端渲染的
HTML
页面时,Nuxt.js
会在客户端重新激活Vue
组件。这意味着页面在加载时将拥有完整的交互功能,并且能够响应用户的交互事件。 - 自动生成路由:
Nuxt.js
根据pages
目录的结构自动生成路由配置,无需手动配置路由。每个.vue
文件会被映射为一个路由页面。 - 异步数据预取:
Nuxt.js
提供了asyncData
方法,用于在渲染页面之前异步获取数据并将其预取到组件中。这样在客户端激活时,页面已经具备了所需的数据,避免了额外的数据请求。
1.2 如何创建一个 Nuxt.js 项目
若想创建一个新的 Nuxt.js 项目,只需按照以下步骤操作:
-
安装
Node.js
和npm
:确保你的计算机上安装了最新版的Node.js
和npm
。 -
安装
create-nuxt-app
:在命令行中执行以下命令安装create-nuxt-app
工具。npm install -g create-nuxt-app
-
创建新项目:使用 create-nuxt-app 工具创建新的
Nuxt.js
项目。执行以下命令,按照提示进行选择。create-nuxt-app my-nuxt-app
在这里,
my-nuxt-app
是你想要创建的项目名称,你可以替换为你喜欢的名称。 -
进入项目目录:创建完项目后,进入项目目录。
cd my-nuxt-app
-
启动开发服务器:执行以下命令来启动开发服务器。
npm run dev
开发服务器会启动,然后就可以在浏览器中访问
http://localhost:3000
来预览Nuxt.js
应用。
2. 百万级爬虫(scrapy框架)
我接手的项目是爬取近一百万条化工品的详细信息,包括中文名称、中文同义词、英文名称、英文同义词、CAS号、分子式、Mol文件、化学性质(熔沸点、密度、蒸汽压)等信息。
我接到的初始化文件是一个存储CAS号的csv文件,由于目标网站使用SSR,所以我采用的技术框架为scrapy,用xpath定位目标元素。
2.1 爬取过程
- 遍历cas号目录,将cas号拼接url,访问化合物详情页
- 使用xpath定位目标元素
图下的xpath是需要优化的,这里是详细路径仅供参考
- scrapy详细使用步骤
安装scrapy
pip install scrapy
创建一个新的Scrapy项目并生成一个Spider。在命令行中执行以下命令:
scrapy startproject chemicalbook
cd chemicalbook
scrapy genspider compounds chemicalbook.com
打开生成的Spider文件compounds.py
,编写爬虫代码。在该Spider中,我们将使用XPath表达式来提取化合物的名称和属性信息。以下是部分v的代码示例:
import scrapy
class CompoundsSpider(scrapy.Spider):
name = 'compounds'
start_urls = ['https://www.chemicalbook.com/ProductChemicalPropertiesCB8854934_EN.htm']
def parse(self, response):
# 使用XPath表达式定位化合物名称和属性信息
compounds = response.xpath('//div[@class="acontent"]/table[@class="acontenttable"]/tr')
for compound in compounds:
name = compound.xpath('td[@class="acontenttd"]/strong/a/text()').get()
properties = compound.xpath('td[@class="acontenttd"]/table[@class="pcontenttable"]/tr')
properties_dict = {}
for prop in properties:
prop_name = prop.xpath('td[1]/text()').get()
prop_value = prop.xpath('td[2]/text()').get()
properties_dict[prop_name] = prop_value
yield {
'Name': name,
'Properties': properties_dict
}
以上代码定义了一个名为compounds
的Spider,它会从给定的URL开始爬取数据。在parse
函数中,我们使用XPath表达式提取化合物的名称和属性信息。然后,我们将提取的数据保存在字典中,并使用yield
关键字将数据逐个输出。
运行Spider的命令如下:
scrapy crawl compounds -o compounds.json
这将启动爬虫并将提取的化合物信息保存到compounds.json
文件中。可以根据需要调整代码,添加更多的XPath表达式来提取其他数据。
2.2 爬取遇到的问题
在爬取的过程我也是遇到了非常多的问题,当时也查阅了大量的资料,最后总结的问题主要是xpath的优化,ip代理池的优化,数据格式清洗等。
封禁IP问题的解决:
- 设置请求头(User-Agent): 伪装浏览器发送请求,避免被网站识别为爬虫。在Scrapy的Spider中,可以通过设置请求头来实现:
class CompoundsSpider(scrapy.Spider):
name = 'compounds'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36'
}
def start_requests(self):
yield scrapy.Request(url='https://www.chemicalbook.com/ProductChemicalPropertiesCB8854934_EN.htm', headers=self.headers)
- 使用代理IP池: 使用代理IP池轮换发送请求,避免频繁请求同一IP地址,降低被封禁的风险。可以使用第三方的代理IP服务或自建代理IP池。我当时是使用的第三方代理,采用的是每隔一段时间调用一个稳定ip的方式。
class CompoundsSpider(scrapy.Spider):
name = 'compounds'
custom_settings = {
'DOWNLOADER_MIDDLEWARES': {
'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 1,
'YourProjectName.middlewares.ProxyMiddleware': 100, # 自定义代理中间件
}
}
def start_requests(self):
yield scrapy.Request(url='https://www.chemicalbook.com/ProductChemicalPropertiesCB8854934_EN.htm')
- 请求延迟: 在发送请求时添加延迟,模拟人的访问行为,避免短时间内发送过多请求。
class CompoundsSpider(scrapy.Spider):
name = 'compounds'
download_delay = 2 # 设置请求延迟为2秒
def start_requests(self):
yield scrapy.Request(url='https://www.chemicalbook.com/ProductChemicalPropertiesCB8854934_EN.htm')
- 监控封禁情况: 监控爬虫运行过程中是否有IP被封禁,如果出现封禁情况,及时停止爬虫运行并调整爬取策略。
数据清洗:
数据清洗主要是做空白去除,去冗余数据。
- 处理重复项: 可以通过使用集合(Set)或数据库的唯一索引来去除重复的数据项。
class CleanDataPipeline:
def __init__(self):
self.seen = set()
def process_item(self, item, spider):
# 去除重复项
if item['Name'] not in self.seen:
self.seen.add(item['Name'])
return item
else:
raise DropItem("Duplicate item found: %s" % item)
- 处理空值: 检查爬取的数据是否存在空值,根据情况可以选择删除、填充或忽略这些数据。
class CleanDataPipeline:
def process_item(self, item, spider):
# 处理空值
if not item['Name']:
raise DropItem("Missing Name in %s" % item)
return item
- 处理无效信息: 检查爬取的数据是否包含异常值或无效信息,例如不符合预期格式的数据。可以根据业务需求进行处理,比如删除或标记这些数据。
class CleanDataPipeline:
def process_item(self, item, spider):
# 处理无效信息
if item['Properties']['Property1'] == 'N/A':
item['Properties']['Property1'] = None
return item
- 数据格式化: 对于爬取的数据进行格式化处理,确保数据的一致性和可读性。
class CleanDataPipeline:
def process_item(self, item, spider):
# 数据格式化
item['Properties']['Property1'] = item['Properties']['Property1'].strip()
return item
以上示例代码给出了一个简单的数据清洗Pipeline(爬虫管道)
3. 千人千面
3.1 埋点
-
用户画像建模: 利用埋点技术收集用户在网站中的行为数据,包括页面浏览、搜索、点击、购买、加入购物车等行为,将这些数据进行处理和分析,构建用户画像。用户画像可以包含用户的兴趣爱好、购买习惯、偏好标签等信息。
-
物品画像建模: 对商品进行标签化和分类,根据商品属性和特征构建物品画像。通过埋点技术收集商品的点击量、购买量等数据,帮助分析商品的热门程度和受欢迎程度。
-
协同过滤和内容推荐算法: 利用用户画像和物品画像,结合协同过滤和内容推荐算法,为用户进行个性化推荐。根据用户的历史行为和标签,找到相似用户和相似商品,为用户推荐可能感兴趣的商品。
-
实时推荐和个性化定价: 利用埋点技术实时跟踪用户的行为,及时更新推荐内容和定价策略。根据用户的实时行为和画像信息,个性化地调整价格优惠,提高用户购买的转化率。
示例代码:
用于在用户点击商品时触发埋点事件,并将点击事件发送到后端进行记录。
<!-- 页面中的商品列表 -->
<div class="item" data-item-id="Item1">
<span>商品1</span>
<button onclick="trackClick('Item1')">点击购买</button>
</div>
<div class="item" data-item-id="Item2">
<span>商品2</span>
<button onclick="trackClick('Item2')">点击购买</button>
</div>
<!-- ...更多商品列表... -->
<script>
// 埋点函数,将用户点击行为发送到后端进行记录
function trackClick(itemId) {
// 发送数据到后端,进行记录
// 示例代码,实际应用中需要发送数据到服务器
console.log(`用户点击了商品 ${itemId}`);
// 可以在此处根据实际业务需求进行更多的数据采集和处理
}
</script>
3.2 标签库
在实际场景中,电商平台可以根据用户的历史行为和画像信息为用户打上不同的标签,例如"高价值用户"、“新用户”、"活跃用户"等。根据不同的用户标签,电商平台可以针对性地提供不同的价格优惠。
示例代码:
from collections import defaultdict
# 模拟用户历史行为数据和画像信息
user_behavior = {
'User1': ['Item1', 'Item2', 'Item3'],
'User2': ['Item2', 'Item4'],
'User3': ['Item1', 'Item3', 'Item5'],
'User4': ['Item2', 'Item3', 'Item4', 'Item5'],
'User5': ['Item1', 'Item5']
}
user_tags = {
'User1': 'VIP',
'User2': 'New',
'User3': 'VIP',
'User4': 'Active',
'User5': 'Active'
}
# 定义不同用户标签对应的价格优惠
price_discount = {
'VIP': 0.8, # VIP用户打八折
'New': 0.9, # 新用户打九折
'Active': 0.95 # 活跃用户打九五折
}
def get_price_discount(user):
tag = user_tags[user]
return price_discount.get(tag, 1.0) # 默认没有标签或其他标签的用户不打折
user = 'User1'
discount = get_price_discount(user)
print(f"用户 {user} 的价格优惠为:{discount}")