七夕将至,Python爬虫分析告诉你到底要送女朋友/男朋友什么礼物

前言

“牛郎织女”的在七夕相会的美丽爱情传说,使七夕成为了象征爱情的节日,同时也被认为是中国最具浪漫色彩的传统节日,在当代更是成为了“中国情人节”的文化符号。
随着七夕的临近,很多小伙伴都开始筹备送女朋友/男朋友的礼物了,礼物作为一种传达情感的媒介,表达了对于女朋友/男朋友的祝福和心意,但同时对于要送什么礼物,对于很多小伙伴来讲倒是选择困难,本文利用 Python 爬取某宝商品页面,为小伙伴们分析销量较高的礼物清单,以供大家参考。
(本文无任何广告行为,仅作为学习分析使用,如侵删。)

程序说明

根据不同关键字,爬取“某宝”获取商品信息(以“七夕礼物”“七夕礼物送男友”“七夕礼物送女友”等为例),根据所获取数据分析得到七夕礼物清单,并通过词云可视化的方式展示不同礼物的频率比重对比。

数据爬取

🕸️ 网址构成分析

爬虫少不了网址,因此首先观察网址的构成,在输入关键字“七夕礼物”进行搜索时,发现网址中 q 的参数值即为所键入的关键字“七夕礼物”,如下图所示:

网址构成分析
因此可以使用以下方式构造网址:

q_value = "七夕礼物"
url = "https://s.taobao.com/search?q={}imgfile=&js=1&stats_click=search_radio_all%3A1&initiative_id=staobaoz_20210802&ie=utf8&bcoffset=5&p4ppushleft=2%2C48&ntoffset=5&s=44".format(q_value)

虽然也可以直接复制网址,但是这种方法的弊端在于,每次想要爬取其他类别的商品时,都需要重新打开网页复制网址;而利用 q_value 变量构造网址,当需要获取其他品类商品时仅需要修改 q_value 变量,例如要爬取关键字“七夕礼物送男友”,只需要做如下修改:

q_value = "七夕礼物送男友"

🕸️ 网页结构分析

使用浏览器“开发者工具”,观察网页结构,可以看出商品的信息都是在 <script> 中,

网页结构
因此,首先使用 requests 库请求网页内容,需要注意的是,在请求页面信息时,需要构造请求头中的 cookieuser-agent 信息,否则并不会得到有效响应,获取 cookieuser-agent 信息需要在浏览器“开发者工具”中的网络标签下单击当前请求页面(如果网络标签下没有当前请求的页面,需要刷新后才可以显示),在标头选项卡中找到请求标头cookieuser-agent 值并复制,按照以下方式构造请求头:

headers = {
	# 将user-agent值,替换为刚刚复制的user-agent值
    "user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 Edg/92.0.902.62",
    # 将cookie值,替换为刚刚复制的cookie值
    "cookie":"...JSESSIONID=4990DB1E8783DF90266F5159209F8E3A"
}

下图显示了获取 cookie 值的示例(获取 user-agent 值的方式类似,只需在标头选项卡中找到请求标头user-agent 值):

构造cookie信息

得到响应网页后,需要使用 BeautifulSoup4 与正则表达库 re 解析网页,获取商品信息:

import re
import  requests
from bs4 import BeautifulSoup

# 请求网页
response = requests.get(url,headers =headers)
response.raise_for_status()
response.encoding = 'utf-8'
# 解析网页
soup = BeautifulSoup(response.text, 'html.parser')
results = soup.find_all('script')
information = str(results[7])

# 获取商品标题
raw_title = re.findall(r'"raw_title":"(.*?)"', information)
# 获取商品价格
view_price = re.findall(r'"view_price":"(.*?)"', information)
# 获取购买人数
view_sales = re.findall(r'"view_sales":"(.*?)"', information)
# 获取发货地址
item_loc = re.findall(r'"item_loc":"(.*?)"', information)
# 获取店铺名
nick = re.findall(r'"nick":"(.*?)"', information)
# 获取详情页地址
detail_url = re.findall(r'"detail_url":"(.*?)"', information)
# 获取封面图片地址
pic_url = re.findall(r'"pic_url":"(.*?)"', information)

需要注意的是,由于一开始使用 utf-8 方式解码网页,并不能解码 Unicode,因此打印详情页地址和封面图片地址会看到解码不正确的情况:

print(detail_url[4])
# //detail.tmall.com/item.htm?id\u003d628777347316\u0026ns\u003d1\u0026abbucket\u003d17

因此需要使用以下方式进行正确解码:

decodeunichars = detail_url[4].encode('utf-8').decode('unicode-escape')
print(decodeunichars)
# //detail.tmall.com/item.htm?id=628777347316&ns=1&abbucket=17

🕸️ 将数据写入csv文件中

为了将数据写入 csv 文件中,首先创建 csv 文件并写入标头:

#创建存储csv文件存储数据
file = open('gift.csv', "w", encoding="utf-8-sig",newline='')
csv_head = csv.writer(file)
#表头
header = ['raw_title','view_price','view_sales','salary','item_loc','nick','detail_url','pic_url']
csv_head.writerow(header)
file.close()

然后,由于英文逗号(",")表示单元格的切换,因此需要将获取的数据经过预处理:

def precess(item):
    return item.replace(',', ' ')

最后将预处理数据后,将数据写入 csv 文件中:

for i in range(len(raw_title)):
    with open('gift.csv', 'a+', encoding='utf-8-sig') as f:
        f.write(precess(raw_title[i]) + ',' 
                + precess(view_price[i]) + ',' 
                + precess(view_sales[i]) + ','  
                + precess(item_loc[i]) +',' 
                + precess(nick[i]) + ','
                + precess(detail_url[i]) + ','
                + precess(pic_url[i]) + '\n')

🕸️ 通过观察页面链接,爬取更多页面

通过查看第2页以及第3页,网址:

https://s.taobao.com/search?q=七夕礼物imgfile=&js=1&stats_click=search_radio_all%3A1&initiative_id=staobaoz_20210805&ie=utf8&bcoffset=1&ntoffset=1&p4ppushleft=2%2C48&s=44
https://s.taobao.com/search?q=七夕礼物&imgfile=&js=1&stats_click=search_radio_all%3A1&initiative_id=staobaoz_20210805&ie=utf8&bcoffset=1&ntoffset=1&p4ppushleft=2%2C48&s=88

可以看到,网址的不同仅在于第二页的 s 的参数值为 44,而第三页 s 的参数值为 88,结合可以每页有 44 个商品,因此可以使用以下方式构造爬取20页商品:

url_pattern = "https://s.taobao.com/search?q={}&imgfile=&js=1&stats_click=search_radio_all%3A1&initiative_id=staobaoz_20210805&ie=utf8&bcoffset=1&ntoffset=1&p4ppushleft=2%2C48&s={}"
for i in range(20):
    url = url_pattern.format(q, i*44)

🕸️ 爬虫程序完整代码

import re
import  requests
import time
from bs4 import BeautifulSoup
import csv
import os

q = "七夕礼物"
url_pattern = "https://s.taobao.com/search?q={}&imgfile=&js=1&stats_click=search_radio_all%3A1&initiative_id=staobaoz_20210805&ie=utf8&bcoffset=2&ntoffset=2&p4ppushleft=2%2C48&s={}"

headers = {
    "user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 Edg/92.0.902.62",
    # cookie值替换为使用上述方式获取的cookie值
    "cookie":"..."
}
    
def analysis(item,results):
    pattern = re.compile(item, re.I|re.M)
    result_list = pattern.findall(results)
    return result_list

def analysis_url(item, results):
    pattern = re.compile(item, re.I|re.M)
    result_list = pattern.findall(results)
    for i in range(len(result_list)):
        result_list[i] = result_list[i].encode('utf-8').decode('unicode-escape')
    return result_list


def precess(item):
    return item.replace(',', ' ')

# 创建csv文件
if not os.path.exists("gift.csv"):
    file = open('gift.csv', "w", encoding="utf-8-sig",newline='')
    csv_head = csv.writer(file)
    #表头
    header = ['raw_title','view_price','view_sales','salary','item_loc','nick','detail_url','pic_url']
    csv_head.writerow(header)
    file.close()

for i in range(100):
    #增加时延防止反爬虫
    time.sleep(25)
    url = url_pattern.format(q, i*44)
    response = requests.get(url=url, headers=headers)
    
    #声明网页编码方式,需要根据具体网页响应情况
    response.encoding = 'utf-8'
    response.raise_for_status()
    soup = BeautifulSoup(response.text, 'html.parser')

    results = soup.find_all('script')
    information = str(results[7])

    # 获取所有的商品信息,由于有些购买人数为空白,导致返回空值,因此添加异常处理
    all_goods = analysis(r'"raw_title":"(.*?)"shopLink"', information)
    for good in all_goods:
        
        # 获取商品标题
        raw_title = analysis(r'(.*?)","pic_url"', good)
        if not raw_title:
            raw_title.append('未命名')
        # 获取商品价格
        view_price = analysis(r'"view_price":"(.*?)"', good)
        if not view_price:
            view_price.append('0.00')
        # 获取购买人数,由于有些购买人数为空白,导致返回空值,因此添加异常处理
        view_sales = analysis(r'"view_sales":"(.*?)"', good)
        #print(view_sales)
        if not view_sales:
            view_sales.append('0人付款')
        # 获取发货地址
        item_loc = analysis(r'"item_loc":"(.*?)"', good)
        if not item_loc:
            item_loc.append('未知地址')
        # 获取店铺名
        nick = analysis(r'"nick":"(.*?)"', good)
        if not nick:
            nick.append('未知店铺')
        # 获取详情页地址
        detail_url = analysis_url(r'"detail_url":"(.*?)"', good)
        if not detail_url:
            detail_url.append('无详情页')
        # 获取封面图片地址
        pic_url = analysis_url(r'"pic_url":"(.*?)"', good)
        if not pic_url:
            pic_url.append('无封面')
        with open('gift.csv', 'a+', encoding='utf-8-sig') as f:
            f.write(precess(raw_title[0]) + ',' 
                    + precess(view_price[0]) + ',' 
                    + precess(view_sales[0]) + ',' 
                    + precess(item_loc[0]) +',' 
                    + precess(nick[0]) + ','
                    + precess(detail_url[0]) + ','
                    + precess(pic_url[0]) + '\n')

🕸️ 爬取数据结果

爬取数据展示

数据分析及可视化

可能很多朋友(并非)是为了学习技术才点击进来的,完(shun)全(bian)是求知若渴的想知道要送男朋友/女朋友什么礼物,别着急,大家最关注的部分来了。
接下来使用词云可视化分析,分别考虑包含销量与不包含销量两种情况。

🎁 七夕礼物清单

不考虑销量时:

from os import path
from PIL import Image
import matplotlib.pyplot as plt
import jieba
from wordcloud import WordCloud, STOPWORDS
import pandas as pd
import matplotlib.ticker as ticker
import numpy as np
import math
import re

df = pd.read_csv('gift.csv', encoding='utf-8-sig',usecols=['raw_title','view_price','view_sales','salary','item_loc','nick','detail_url','pic_url'])

raw_title_list = df['raw_title'].values
raw_title = ','.join(raw_title_list)
with open('text.txt','a+') as f:
    f.writelines(raw_title)

###当前文件路径
d = path.dirname(__file__)

# Read the whole text.
file = open(path.join(d, 'text.txt')).read()
##进行分词
#停用词,去除修饰性的词
stopwords = ["七夕","七夕情人节","情人节","男友","女友","男生","女生","女朋友","男朋友","礼物","生日礼物","创意","实用","朋友","男士","老婆","老公","直营","闺蜜","结婚","送给"]
text_split = jieba.cut(file)  # 未去掉停用词的分词结果   list类型

#去掉停用词的分词结果  list类型
text_split_no = []
for word in text_split:
    if word not in stopwords:
        text_split_no.append(word)
#print(text_split_no)

text =' '.join(text_split_no)
#背景图片
picture_mask = np.array(Image.open(path.join(d, "beijing.jpg")))
stopwords = set(STOPWORDS)
stopwords.add("said")
wc = WordCloud(  
    #设置字体,指定字体路径
    font_path=r'C:\Windows\Fonts\simsun.ttc',
    background_color="white",   
    max_words=4000,   
    mask=picture_mask,  
    stopwords=stopwords)  
# 生成词云
wc.generate(text)

# 存储图片
wc.to_file(path.join(d, "result.jpg"))

可视化
接下来考虑销量:

def get_sales(item):
    tmp = item[:-3]
    if '万' in tmp:
        tmp = tmp.replace('万','0000').replace('.','')
    if '+' in tmp:
        tmp = tmp.replace('+','')
    tmp = int(tmp)
    tmp = tmp / 100.0
    if tmp <= 0:
        tmp = 0
    tmp = round(tmp)
    return tmp
    
raw_title_list = df['raw_title'].values
view_sales_list = df['view_sales'].values
for i in range(len(raw_title_list)):
    for j in range(get_sales(view_sales_list[i])):
        with open('text.txt','a+') as f:
            f.writelines(raw_title_list[i]+',')
# 其余代码不再赘述
"""
...
"""

请添加图片描述

可以看到差别还是较为明显的,最后将分词结果,进行排序,手动去除无效词后,归类整理出排名前15的礼物清单:

gift = {}
for i in text_split_no:
	if gift.get(i,0):
		gift[i] += 1
	else:
		gift[i] = 1
sorted_gift = sorted(gift.items(), key=lambda x:x[1],reverse=True)

❤️礼物清单❤️

玩偶/公仔/毛绒玩具/抱抱熊
糖果
项链
巧克力
相册/纪念册
零食/小吃
手链/手镯/镯子
玫瑰
吊坠
小夜灯
音乐盒/八音盒
戒指/对戒
口红
手绳/红绳
耳钉

👧 送女朋友礼物清单

以同样的方法,将关键字改为“女友+礼物”,可以得到❤️送女朋友礼物清单❤️:

小夜灯
相册/纪念册/相框
刻字类礼物
八音盒
项链/手链/手镯/镯子
口红
手表
包
水晶鞋
玩偶

👦 送男朋友礼物清单

最后,将关键字改为“男友+礼物”,可以得到❤️送男朋友礼物清单❤️:

可乐刻字
相册/纪念册/相框
花束
手办
摆件
钥匙扣
木刻画
情书
刺绣
篮球

可以看出,送女朋友和男朋友的礼物还是有一些差别的。
当然,和主管感觉上有很些差异的原因可能在于,很多商品的标题太过创意,完全不包含商品。

下一步计划

下一步的工作包括:

  1. 获取商品的评价信息,将购买者的评论信息也融合到计算权重中去,根据购买者的评价对商品排序进行修正,例如可能去除一些华而不实的“智商税”产品,同时可能得到一些小众好评的商品。
  2. 利用深度学习相关技术,识别图片中商品,用以解决一些商品标题及商品图片文字中完全不包含商品名的情况,让我们明白标题为《生日礼物女生七夕情人节给闺蜜送女友朋友送给女孩的实用小高级感》的商品到底卖的是什么?

写在最后

当然,本文仅做分析之用,结果也仅供参考,如果清单里没有令你心仪的礼物,也可以选择红包或者清空购物车的方式。无论送女朋友/男朋友什么礼物,传达自己的❤️心意❤️最重要了。

  • 125
    点赞
  • 102
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 215
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 215
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

盼小辉丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值