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

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

作者: 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接入


    【五】总结分析

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

    仅用于记录个人工作。


    相关文章

      网友评论

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

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