美文网首页
天猫(林氏木业旗舰店)竞品数据获取项目

天猫(林氏木业旗舰店)竞品数据获取项目

作者: Ziger丶 | 来源:发表于2019-03-05 20:49 被阅读0次

背景:因营销需求,对家具市场近期活动有明确的了解,分析出近期对手上新的产品&活动力度。
数据:天猫林氏木业旗舰店各类家具商品的详细信息,包括但不限于产品详细信息,价格,销量,评论量,图片。
目标:编写爬虫框架,定期获取目标数据,导入数据库。分析出热销产品的关键因素,活动折扣力度。为图片打上标签,以便后期对比划分,调整节日期间活动。

爬取目标

【一】思路

1、爬虫:观察目标网址检查后发现数据信息通过js隐藏,需要导出其实际跳转网址进行爬取。
2、分析:清洗数据&特征工程后,分析出热销产品的关键点。结合活动力度找出提升销量的关键因素。
3、分类:直接使用百度AI


【二】项目流程


【三】爬虫代码

1.获取商品的主要分类链接
分类
子分类

直接获取分类的链接,生成表格

主链接表格
2.根据主链接爬取异步加载的链接
# 提取主分类链接的ID
def ID (X):
    import pandas as pd
    import re
    patter = 'category-(.*).htm?'
    A = []
    for i in range(len(X['子分类链接'])):
        A.append(re.findall(patter, X['子分类链接'][i]))
    A=pd.DataFrame(pd.Series(A),columns=['ID'])
    X =  pd.concat([X,A],axis = 1)
    return(X)

# 提取网址中的编码
def Encode (X):
    import pandas as pd
    A = []
    for i in range(len(X['子分类'])):
        a = X['子分类'][i].encode('gb2312')
        a = str(a)
        a = a.replace('\\x','%')
        a = a.strip("b'")
        A.append(a)
    A = pd.DataFrame(pd.Series(A), columns=['url编码'])
    X = pd.concat([X, A], axis=1)
    return (X)

再将ID与编码拼接成异步链接网址

# 生成对应分类的异步加载链接
def URL (X):
    import pandas as pd
    A = []
    for i in range(len(X['ID'])):
        a = 'https://lshmy.tmall.com/i/asynSearch.htm?_ksTS=1537406700485_954&\
    callback=jsonp955&mid=w-14434271715-0&wid=14434271715&path=/category-[ID]\
    .htm&search=y&keyword=[cat]&scene=taobao_shop&catId=[ID]&scid=[ID]'
        b = a.replace('[ID]',X['ID'][i][0])
        b = b.replace('[cat]',X['url编码'][i])
        A.append(b)
    A = pd.DataFrame(pd.Series(A), columns=['异步加载'])
    X = pd.concat([X, A], axis=1)
    return (X)
异步链接
3.获取所有子分类链接
翻页

考虑到翻页情况,在需要翻页的网址后面写上page。

# 生成子分类的链接, X = 异步链接
def URL_classify (X) :
    import pandas as pd
    import requests
    from lxml import etree
    url_classify = []
    for i in X['异步加载']:
        url_classify.append(i)
        r = requests.get(i)
        A = etree.HTML(r.text)
        B = A.xpath('/html/body/div/div[3]/div/a/text()')
        if B != []:
            B.remove('1')
            if '上一页' in B:
                B.remove('上一页')
            if '下一页' in B:
                B.remove('下一页')
            if B != []:
                for j in B:
                    C = i + '&pageNo=' +j
                    url_classify.append(C)
        print('--' * 20)
    url_classify = pd.DataFrame(pd.Series(url_classify), columns=['分类链接'])
    return (url_classify )
4.获取产品的链接&ID

根据所有子类的链接,获取所有产品的详细地址。

#根据子分类的链接,爬取货物的详细链接,X = 分类链接
def URL_detailed (X):
    import requests
    from lxml import etree
    import pandas as pd
    import re

    url_2 = []
    for i in X['分类链接']:
        r = requests.get(i)
        A = etree.HTML(r.text)
        B = A.xpath('/html/body/div/div[3]/div/dl/dd/a/@href')
        while '\\"javascript:;\\"' in B:
            B.remove('\\"javascript:;\\"')
        url_2.append(B)
        print ('-'*40)
    url_detailed = []
    for i in url_2 :
        for j in i:
            url_detailed.append(j)
    url_detailed_2 = []
    for i in url_detailed:
        i = i.strip('\\"')
        i = 'https:' + i +'&tdsourcetag=s_pctim_aiomsg&sku_properties=21433:50753410;10142888:302694851'
        url_detailed_2.append (i)
    url_detailed_2 = pd.DataFrame(pd.Series(url_detailed_2), columns=['货物链接'])
    return (url_detailed_2)

# 根据货物的链接,爬取货物的ID,X = 货物链接
def ID_detailed (X):
    import pandas as pd
    import re
    patter = 'id=(.*)&rn'
    A = []
    for i in X['货物链接']:
        A.append(re.findall(patter, i))
    A = pd.DataFrame(pd.Series(A), columns=['货物ID'])
    return(A)

产品链接
5.获取产品的详细属性

查看需要获取的属性,将其整合成列表。在爬取过程中生成对应的键值对。


产品属性
#根据货物的详细链接,爬去货物的属性信息,X = 货物详细链接表
def Label (X):
    import pandas as pd
    import re
    import requests
    from lxml import etree
    requests.adapters.DEFAULT_RETRIES = 5
    d1 =['包装体积:','型号:','是否预售:','款式定位:','颜色分类:','尺寸:','是否带储物空间:','填充物:','是否带软靠:',\
         '是否可定制:','材质:','风格:','家具结构:']
    label = []
    number = 0
    headers = {
            'Connection':'close',
            'user-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/54.0.2840.99 Safari/537.36',
            'cookie':'cna=P+QpFIBjZRECAd3tmK78L147; _m_h5_tk=fb7756c8ab31726f5bf669b649827a44_1537527405908; _m_h5_tk_enc=69ada9216bd726de6e5e7b6bd87bc923; t=eba31fabfb5d9e662f3140dda391b1c2; _tb_token_=ed137f8e33b3a;cookie2=147853597cf22040f4cc675132589da6; pnm_cku822=098%23E1hvMpvUvbpvUvCkvvvvvjiPPsS96jtbR2MpQjthPmP9tj1hP2dOtjnjPFdyzjtbRphvCvvvphvEvpCW99K0r30gRbutnV3Xibm0HskTWlK91Ep7%2BulAbMo6eCOtHjnNAbmAdBeK4Z7xfBeK5dXKjdzCHEp7%2B3%2BuaNpArqVTbZkt640AdByapbyCvm9vvhCvvvvvvvvvBJZvvUhCvvCHtpvv9ZUvvhcDvvmCb9vvBJZvvUhKkphvC9hvpyPZ68yCvv9vvhh5RPb9YQhCvvOv9hCvvvvPvpvhvv2MMTwCvvpvvhHh; cq=ccp%3D1; isg=BKqqBC3Mhcz5IwmrkTMwD7HR-xCMsy_cRtO92TRjHP2CZ0ohHKgmhLmV89Nel6YN'
            }
    for  i in X ['货物链接'] :
        r = requests.session()
        r.keep_alive = False
        r = requests.get(i,timeout = 10,headers = headers)
        A = etree.HTML(r.text)
        B = A.xpath('//*[@id="J_AttrUL"]/li/text()')
        C = ''
        for j in B:
            j = '-' + j + '-'
            C = C + j
        C = C.replace('\xa0','')
        _属性={}
        for k in d1:
            A = re.findall('-%s(.*?)-'%k,C)
            if A == []:
                A = 'NAN'
            else :
                A = A[0]
            _属性.update({k:A})
        label.append(_属性)
        number += 1
        print ('---'*20 + str(number))
    label = pd.DataFrame(label)
    return (label)
产品属性列表
5.获取产品的评论量
累计评论量

观察页面的信息,发现累计评价是通过加载json文件进行传输的。页面中找到对应的网址,观察发现是由于链接最后的ID变动导致的。

json的链接 json文件

其中设置断连判断,如果链接断开的话,就进行睡眠。

def Comment (X):
    requests.adapters.DEFAULT_RETRIES = 5
    r = requests.session()
    r.keep_alive = False
    url = 'https://dsr-rate.tmall.com/list_dsr_info.htm?itemId='
    comment = []
    number = 0
    for i,j in zip(X['货物ID'],X['货物链接']):
        i = i.strip("[]'")
        A = url + i
        B = []
        headers = {
            "Referer":j,
            'cookie':'cna=P+QpFIBjZRECAd3tmK78L147; _m_h5_tk=fb7756c8ab31726f5bf669b649827a44_1537527405908; _m_h5_tk_enc=69ada9216bd726de6e5e7b6bd87bc923; t=425bdd5592c604f0d691f808f0a844b1; _tb_token_=73137373e63e8; cookie2=10d98d0bd350def7bc50f0880033ce61; isg=BGNjUSgJPOPwC_DccBAZECAC8qfN8PYzV6AkDpXDFUIy1ID2HSkK6nBFysT_9E-S',
            'user-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'
                    }
        try:
            r = requests.get(A,timeout = 10,headers = headers)
            B = re.findall('"rateTotal":(.*?)}',r.text)
            comment.append(B)
            number += 1
            print ('---'*20 + str(number))
        except:
#                print("Connection refused by the server..")
#                print("Let me sleep for 5 seconds")
            print("ZZzzzz...")
            time.sleep(5)
            print("Was a nice sleep, now let me continue...")
    comment = pd.DataFrame(pd.Series(comment), columns=['评论数量'])
    return (comment)
6.获取产品的价格

同理根据隐藏拼接即可获取相应的价格。


7.下载图片

将先前获取的图片链接逐一清洗出来,再进行下载。

#清洗出图片地址,X = 产品包含的图片地址
def JPG_url (X):
    jpg_url = []
    for i in X['图片']:
        if ',' not in i:
            url = 'http:' + i.strip(r"[]'")
            jpg_url.append(url)
        else :
            i = i.replace("'",'')
            i = i.strip(r"[]'")
            i = i.split(',')
            for j in i:
                j = j.strip()
                url = 'http:' + j
                jpg_url.append(url)
    #jpg_url = pd.DataFrame(pd.Series(jpg_url), columns=['图片下载地址'])
    return (jpg_url)

#通过图片地址,将图片下载到本地,X = 每张图片的下载地址
def JPG (X):
    import os
    number = 1
    for i in X['图片下载地址']:
        url = i
        #图片存储的地址
        root = "G://python//"
        path = root + url.split("/")[-1]
        try:
            if not os.path.exists(root):
                os.mkdir(root)
            if not os.path.exists(path):
                r = requests.get(url,timeout = 10)
                r.raise_for_status()
                #使用with语句可以不用自己手动关闭已经打开的文件流
                with open(path,"wb") as f: #开始写文件,wb代表写二进制文件
                    f.write(r.content)
                print("爬取完成" + '---'*20 +str(number))
                number += 1
            else:
                print("文件已存在")
        except Exception as e:
            print("爬取失败:"+str(e))
        else :
            time.sleep(1)
    return ('爬取完成')
8.导入数据库

python导入DB2数据库时,需要调整ibm_db包,点我查看


【三】建模分析

1.数据探索

获取数据后观察现有的数据:
1.、这是家具类产品的数据,是消费者能获取的最直观的信息。
2、有什么类型的feature:产品名称、图片、产品属性('包装体积:','型号:','是否预售:','款式定位:','颜色分类:','尺寸:','是否带储物空间:','填充物:','是否带软靠:','是否可定制:','材质:','风格:','家具结构: 等)、价格(市场价格,本站价格)、评论(评论量,最近评论时间)、销量、活动(折扣,活动名称)。这些都 目前可以获取的信息 。

再问几个问题:
1.相同的产品,不同的名称会不会导致在train和test中重复?
2.数据在时间上的分布是否会有影响?
3.有多少价格区间,价格区间如何划分,产品的风格种类有哪些?不同类型的产品是否会随时间的变化?
4.活动对销量的影响如何判定?
5.近期什么样的产品是最受欢迎的?

以上都是需要与业务部门同事交流探讨后确定的重要维度。


2.数据清洗

剔除缺失值明显的数据,数据归一化,文字类型数据转化成数字类型数据。

def Sigmoid (X):
    return (1.0 / (1 + np.exp(-float(X)));

def Replace (X,columns):
    a = X.groupby([columns],as_index=False)[columns].agg({'cnt':'count'})
    for i in a[columns]:
        X[columns] = X[columns].replace(i,a[(a[columns]== i )].index.tolist()[0])
    return (X)

3.特征工程

个人认为特征工程是建模分析的重中之重,模型大同小异,基本是都是调用几种开源框架。所以,模型都差不多,特征就是关键了。
利用模型自带的feature_importance_,写出一个特征选择函数:

#alg:模型,columns:特征集合
def select_important_features(alg,columns): 
    importances=zip(map(lambda x: round(x, 4), alg.feature_importances_), columns)
    importance=[]
    sum=0
    for i in importances:
        if i[0]>0.008:
            importance.append(i[1]) 
            sum=sum+i[0]
    print("Num : %f | Sum: %3f" % (len(importance), sum))
    return importance
importance = select_important_features(rfr,x_train.columns)

每个模型都有独特的业务背景,想要发现甚至是自己创造出重要的特征,往往需要深厚的业务逻辑&行业经验

比如这个项目要预测沙发产品,沙发大小&储物空间大小的比列,就需要通过原始数据进行创造。
当然一切还需要参考业务部门的逻辑&意见。

一般进行特此选择可以参考常用特征的选择方式


4.模型选择&调参

本次测试中选用的是LightGBM模型,模型的性能与准确率都较好。当然为了提高效果的话,应当多个模型比较。

LightGBM

  • num_leaves: 叶子节点的个数
  • max_depth:最大深度,控制分裂的深度
  • learning_rate: 学习率
  • objective: 损失函数(mse, huber loss, fair loss等)
  • min_data_in_leaf: 叶子节点必须包含的最少样本数
  • feature_fraction: 训练时使用feature的比例
  • bagging_fraction: 训练时使用样本的比例

调整参数还是需要一些玄学,想要找到最佳的参数很多时候需要一些经验运气


5.模型融合
  1. Averaging
    Averaging融合方式就是加权平均。格局模型的多样性,平均后长补短,更准确第提高模的泛化能力。
  2. Stacking
    Stacking个人认为就是将第一层模型的结果作为第二层模型的特征,然后训练第二层模型得到最终结果。
    详细解释

6.分析呈现

测试后,根据相应的得分结果选择模型。(分类:混合矩阵、f1_score 。回归:rmse、rmae、r2_score )
直接使用帆软,将导入的结果以BI报表的形式呈现。


【四】分类打标

1.图像识别分类

目前根据业务部门需求,需要将竞品按照风格,类型等划分入不同的标签。
经过部门沟通后,选择百度 EasyDL进行图像划分。方便业务部门进行操作。

百度 EasyDL

根据自有图片进行训练,多次校准。可以将竞品的图片划分入现有的风格分类。


训练的模型

多次训练后,选择适合的版本可以有效的划分相应的家具产品分类。


沙发产品划分结果

对模型进行多次修正,直到效果满足预期,然后接入API接口,自动返回比对结果。
API的接入参考----百度easyDL API接入


【五】总结分析

本次项目中主要侧重的是数据的获取与处理方面。
建模分析是基于业务部门的支持,产品数据的调整很大一部分都来自于业务逻辑的经验之谈。
因为部分原因,不能展示数据结果,分析部分只能说明思路。

仅用于记录个人工作。


相关文章

  • 天猫(林氏木业旗舰店)竞品数据获取项目

    背景:因营销需求,对家具市场近期活动有明确的了解,分析出近期对手上新的产品&活动力度。数据:天猫林氏木业旗舰店各类...

  • 天猫京东淘宝网店第3方独立电商网站案例:林氏木业

    天猫京东淘宝网店第3方独立电商网站案例#林氏木业 为什么选这个案例?很简单,林氏木业(linshimuye.cn)...

  • 20210423-竞品分析收集竞品数据

    在竞品分析之前需要对选择的竞品所在的市场进行分析,这个时候需要考虑的就是竞品数据的获取。竞品数据的分类可以根据行业...

  • 这或许是最全面的竞品分析资料!

    目录 1. 竞品分析目的 2. 竞品分析定义 3. 竞品选取标准 4. 竞品获取渠道 5. 竞品获取内容 6. 竞...

  • 抢单人沙发

    昨天去林氏木业实体店看家具,本来是冲着床和餐桌去的,没想到在试做一张椅子时,无法自拔的喜欢上了。出了林氏木业,天色...

  • 市场与竞品分析(2)-竞品分析 3.3

    什么是竞品分析? 对竞争对手的产品进行分析比较 竞品分析的流程? 明确目的,寻找竞品,确定维度,获取数据,对比分析...

  • iOS frida-ios-dump 砸壳记录

    背景: 最近在做竞品的对比测试,需要获取竞品的iOS安装包,然后逆向代码注入获取性能数据的dylib。但是从App...

  • 林氏木业鲨滩造乐节,趁年轻浪起来

    最近的林氏木业越来越会玩了,年轻人喜欢什么,它就玩什么!如今不惧炎夏,燥乐无穷。趁着天猫超级品牌日,无乐不造之鲨滩...

  • EasyMock例子

    使用easyMock高级语法,测试响应式数据 此模拟接口的目的为获取竞品报告,返回店铺诊断结果,竞品诊断结果,报告...

  • 生意参谋 App

    需求 帮朋友做一个生意参谋的软件,需求如下。 首先选中两个竞品 再把更新时间选为日,获取每一天的数据再合并 竞品入...

网友评论

      本文标题:天猫(林氏木业旗舰店)竞品数据获取项目

      本文链接:https://www.haomeiwen.com/subject/fvhonftx.html