Python爬虫+数据可视化:分析唯品会商品数据

目录

  • 前言
  • 数据来源分析
      • 1. 明确需求
      • 2. 抓包分析:通过浏览器自带工具: 开发者工具
  • 代码实现步骤: 发送请求 -> 获取数据 -> 解析数据 -> 保存数据
      • 发送请求
      • 解析数据
      • 保存数据
  • 数据可视化
      • 先读取数据
      • 泳衣商品性别占比
      • 商品品牌分布占比
      • 各大品牌商品售价平均价格
      • 各大品牌商品原价平均价格
      • 唯品会泳衣商品售价价格区间

前言

唯品会是中国领先的在线特卖会电商平台之一,它以“品牌特卖会”的模式运营,为会员提供品牌折扣商品。唯品会的商品包括服装、鞋类、箱包、美妆、家居、母婴、食品等各类品牌产品。

这就是今天的受害者,我们要拿取上面的泳衣数据,然后可以做些数据可视化

数据来源分析

1. 明确需求

  • 明确采集网站以及数据
    网址: https://category.vip.com/suggest.php?keyword=%E6%B3%B3%E8%A1%A3&ff=235|12|1|1
    数据: 商品信息

2. 抓包分析:通过浏览器自带工具: 开发者工具

  • 打开开发者工具: F12 / 右键点击检查选择network
  • 刷新网页: 让网页数据重新加载一遍
  • 搜索关键字: 搜索数据在哪里
    找到数据包: 50条商品数据信息
    整页数据内容: 120条 --> 分成三个数据包
    1. 前50条数据 --> 前50个商品ID
    2. 中50条数据 --> 中50个商品ID
    3. 后20条数据 --> 后20个商品ID

已知: 数据分为三组 --> 对比三组数据包请求参数变化规律
请求参数变化规律: 商品ID
分析找一下 是否存在一个数据包, 包含所有商品ID

如果想要获取商品信息 --> 先获取所有商品ID --> ID存在数据包

代码实现步骤: 发送请求 -> 获取数据 -> 解析数据 -> 保存数据

发送请求

我们定义了要爬取的URL地址,并设置了User-Agent请求头,以模拟浏览器发送请求。
使用requests.get方法发送GET请求,并将响应保存在response变量中。

headers = {
    # 防盗链 告诉服务器请求链接地址从哪里跳转过来
    'Referer': 'https://category.vip.com/',
    # 用户代理, 表示浏览器基本身份信息
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)'
}
# 请求链接
url = 'https://mapi.vip.com/vips-mobile/rest/shopping/pc/search/product/rank'
data = {
    # 回调函数
    # 'callback': 'getMerchandiseIds',
    'app_name': 'shop_pc',
    'app_version': '4.0',
    'warehouse': 'VIP_HZ',
    'fdc_area_id': '104103101',
    'client': 'pc',
    'mobile_platform': '1',
    'province_id': '104103',
    'api_key': '70f71280d5d547b2a7bb370a529aeea1',
    'user_id': '',
    'mars_cid': '1689245318776_e2b4a7b51f99b3dd6a4e6d356e364148',
    'wap_consumer': 'a',
    'standby_id': 'nature',
    'keyword': '泳衣',
    'lv3CatIds': '',
    'lv2CatIds': '',
    'lv1CatIds': '',
    'brandStoreSns': '',
    'props': '',
    'priceMin': '',
    'priceMax': '',
    'vipService': '',
    'sort': '0',
    'pageOffset': '0',
    'channelId': '1',
    'gPlatform': 'PC',
    'batchSize': '120',
    '_': '1689250387620',
}
# 发送请求 --> <Response [200]> 响应对象
response = requests.get(url=url, params=data, headers=headers)

解析数据

然后,我们定义了起始标签和结束标签,通过循环的方式遍历文本,并提取每个商品的名称和价格。

# 商品ID -> 120个
products = [i['pid'] for i in response.json()['data']['products']]
# 把120个商品ID 分组 --> 切片 起始:0 结束:50 步长:1
# 列表合并成字符串
product_id_1 = ','.join(products[:50]) #  提取前50个商品ID 0-49
product_id_2 = ','.join(products[50:100]) #  提取中50个商品ID 50-99
product_id_3 = ','.join(products[100:]) #  提取后20个商品ID 100到最后
product_id_list = [product_id_1, product_id_2, product_id_3]

for product_id in product_id_list:
    # 请求链接
    link = 'https://mapi.vip.com/vips-mobile/rest/shopping/pc/product/module/list/v2'
    # 请求参数
    params = {
        # 'callback': 'getMerchandiseDroplets2',
        'app_name': 'shop_pc',
        'app_version': '4.0',
        'warehouse': 'VIP_HZ',
        'fdc_area_id': '104103101',
        'client': 'pc',
        'mobile_platform': '1',
        'province_id': '104103',
        'api_key': '70f71280d5d547b2a7bb370a529aeea1',
        'user_id': '',
        'mars_cid': '1689245318776_e2b4a7b51f99b3dd6a4e6d356e364148',
        'wap_consumer': 'a',
        'productIds': product_id,
        'scene': 'search',
        'standby_id': 'nature',
        'extParams': '{"stdSizeVids":"","preheatTipsVer":"3","couponVer":"v2","exclusivePrice":"1","iconSpec":"2x","ic2label":1,"superHot":1,"bigBrand":"1"}',
        'context': '',
        '_': '1689250387628',
    }
    # 发送请求
    json_data = requests.get(url=link, params=params, headers=headers).json()
    for index in json_data['data']['products']:
        # 商品信息
        attr = ','.join([j['value'] for j in index['attrs']])
        # 创建字典
        dit = {
            '标题': index['title'],
            '品牌': index['brandShowName'],
            '原价': index['price']['marketPrice'],
            '售价': index['price']['salePrice'],
            '折扣': index['price']['mixPriceLabel'],
            '商品信息': attr,
            '详情页': f'https://detail.vip.com/detail-{index["brandId"]}-{index["productId"]}.html',
        }
        csv_writer.writerow(dit)
        print(dit)

保存数据

然后,我们使用open函数创建一个CSV文件,并指定文件名、写入模式、编码方式等参数。然后使用csv.DictWriter初始化一个写入器对象,并指定表头。

我们使用writer.writeheader()来写入CSV文件的表头,然后遍历items列表,使用writer.writerow()将每个商品的数据写入CSV文件中。

f = open('商品.csv', mode='a', encoding='utf-8', newline='')
csv_writer = csv.DictWriter(f, fieldnames=[
    '标题',
    '品牌',
    '原价',
    '售价',
    '折扣',
    '商品信息',
    '详情页',
])
csv_writer.writeheader()

数据可视化

先读取数据

df = pd.read_csv('商品.csv')
df.head()

泳衣商品性别占比

from pyecharts import options as opts
from pyecharts.charts import Bar
from pyecharts.faker import Faker


c = (
    Bar()
    .add_xaxis(sex_type)
    .add_yaxis("", sex_num)
    .set_global_opts(
        title_opts=opts.TitleOpts(title="泳衣商品性别占比", subtitle=""),
        brush_opts=opts.BrushOpts(),
    )
)
c.load_javascript()

from pyecharts import options as opts
from pyecharts.charts import Pie

c = (
    Pie()
    .add("", [list(z) for z in zip(sex_type, sex_num)])
    .set_global_opts(title_opts=opts.TitleOpts(title="泳衣商品性别占比"))
    .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}"))
)
c.render_notebook()

商品品牌分布占比

shop_num = df['品牌'].value_counts().to_list()
shop_type = df['品牌'].value_counts().index.to_list()
c = (
    Pie()
    .add(
        "",
        [
            list(z)
            for z in zip(shop_type, shop_num)
        ],
        center=["40%", "50%"],
    )
    .set_global_opts(
        title_opts=opts.TitleOpts(title="商品品牌分布占比"),
        legend_opts=opts.LegendOpts(type_="scroll", pos_left="80%", orient="vertical"),
    )
    .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}"))
)
c.render_notebook()

各大品牌商品售价平均价格

# 按城市分组并计算平均薪资
avg_salary = df.groupby('品牌')['售价'].mean()
ShopType = avg_salary.index.tolist()
ShopNum = [int(a) for a in avg_salary.values.tolist()]
# 创建柱状图实例
c = (
    Bar()
    .add_xaxis(ShopType)
    .add_yaxis("", ShopNum)
    .set_global_opts(
        title_opts=opts.TitleOpts(title="各大品牌商品售价平均价格"),
        visualmap_opts=opts.VisualMapOpts(
            dimension=1,
            pos_right="5%",
            max_=30,
            is_inverse=True,
        ),
        xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45))  # 设置X轴标签旋转角度为45度
    )
    .set_series_opts(
        label_opts=opts.LabelOpts(is_show=False),
        markline_opts=opts.MarkLineOpts(
            data=[
                opts.MarkLineItem(type_="min", name="最小值"),
                opts.MarkLineItem(type_="max", name="最大值"),
                opts.MarkLineItem(type_="average", name="平均值"),
            ]
        ),
    )
)

c.render_notebook()

各大品牌商品原价平均价格

# 按城市分组并计算平均薪资
avg_salary = df.groupby('品牌')['原价'].mean()
ShopType_1 = avg_salary.index.tolist()
ShopNum_1 = [int(a) for a in avg_salary.values.tolist()]
# 创建柱状图实例
c = (
    Bar()
    .add_xaxis(ShopType_1)
    .add_yaxis("", ShopNum_1)
    .set_global_opts(
        title_opts=opts.TitleOpts(title="各大品牌商品原价平均价格"),
        visualmap_opts=opts.VisualMapOpts(
            dimension=1,
            pos_right="5%",
            max_=30,
            is_inverse=True,
        ),
        xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45))  # 设置X轴标签旋转角度为45度
    )
    .set_series_opts(
        label_opts=opts.LabelOpts(is_show=False),
        markline_opts=opts.MarkLineOpts(
            data=[
                opts.MarkLineItem(type_="min", name="最小值"),
                opts.MarkLineItem(type_="max", name="最大值"),
                opts.MarkLineItem(type_="average", name="平均值"),
            ]
        ),
    )
)

c.render_notebook()

唯品会泳衣商品售价价格区间

pie1 = (
    Pie(init_opts=opts.InitOpts(theme='dark',width='1000px',height='600px'))
    
    .add('', datas_pair_2, radius=['35%', '60%'])
    .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}:{d}%"))
    .set_global_opts(
        title_opts=opts.TitleOpts(
            title="唯品会泳衣商品\n\n售价价格区间", 
            pos_left='center', 
            pos_top='center',
            title_textstyle_opts=opts.TextStyleOpts(
                color='#F0F8FF', 
                font_size=20, 
                font_weight='bold'
            ),
        )
    )
    .set_colors(['#EF9050', '#3B7BA9', '#6FB27C', '#FFAF34', '#D8BFD8', '#00BFFF', '#7FFFAA'])
)
pie1.render_notebook() 

👇问题解答 · 源码获取 · 技术交流 · 抱团学习请联系👇

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/45432.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

macOS mysql 8.0 忘记密码

╰─➤ mysql -V mysql Ver 8.0.33 for macos13.3 on arm64 (Homebrew)mysql.server status mysql.server stopskip-grant-tables 启动mysql ─➤ /opt…

通达信有价值的资金流向指标公式-通达信公式

资金流向指标公式&#xff1a; 流通:AMOUNT/VOL; PJJ:DMA((HIGHLOWCLOSE*2)/4,0.9); JJ:REF(EMA(PJJ,3),1); QJJ:VOL/((HIGH-LOW)*2-ABS(CLOSE-OPEN)); XVL:(IF(CLOSE>OPEN,QJJ*(HIGH-LOW),IF(CLOSE<OPEN,QJJ*(HIGH-OPENCLOSE-LOW),VOL/2))IF(CLOSE>OPEN,0-QJJ*(…

Django框架:使用channels实现websocket,配置和项目实际使用

一、基本配置 依赖包&#xff1a; Django3.2 django-cors-headers3.5.0 redis4.6.0 #操作redis数据库的 channels3.0.0 #websocket channels-redis4.1.0 #通道层需要&#xff0c;依赖redis包项目目录结构&#xff1a; study_websocket --study_websocket --__init__.py --s…

redis 第一章

目录 1.redis 安装部署 2.redis 数据库常用命令 3.总结 1.redis 安装部署 2.redis 数据库常用命令 3.总结 redis&#xff08;远程字典服务器&#xff09;是一个开源的、使用 C 语言编写的 nosql 数据库。redis 基于内存运行并支持持久化&#xff0c;采用 key-value&#xff0…

华为战略方法论:BLM模型之关键任务与依赖关系

内容简介 在 BLM 模型中&#xff0c;执行部分包括四个模块&#xff0c;分别是&#xff1a; 关键任务与依赖关系&#xff1b;组织与绩效&#xff1b;人才&#xff1b;氛围与文化。 详细内容&#xff0c;大家可以参看下面这张图。 这四个模块其实是可以进一步划分成两个关键点…

JavaWeb开发(后端Web开发【一】)

文章目录 前言一、Maven1.Maven概述-介绍1.1.Maven概述-介绍1.2.Maven概述-安装 2.IDEA集成Maven2.1.IDEA集成Maven-配置Maven环境2.2.IDEA集成Maven-创建Maven项目2.3.IDEA集成Maven-导入Maven项目 3.Maven-依赖管理3.1.Maven-依赖管理-依赖配置3.2.Maven-依赖管理-依赖传递3.…

九五从零开始的运维之路(其二十五)

文章目录 前言一、概述二、配置环境及搭建服务1.关闭防火墙、网络图形化工具及SElinux2.配置yum源3.测试网络连通性4.分配磁盘容量5.安装targetcli包6.服务器端进行配置7.客户端 总结 前言 本篇将简述的内容&#xff1a;Linux系统下的ISCSI服务 一、概述 iscsi全称&#xff1…

笔试题:统计字符串中某字符串在其出现的字符个数

笔试题&#xff1a;统计字符串中某一子串的字符个数&#xff1a;例如字符串aabbcd,有aabb:4,ab:2 哈哈&#xff0c;这道题是小编面试音视频龙头企业的笔试题&#xff0c;以下是我写的代码&#xff1a;如果有错误&#xff0c;希望可以指正!!! 解题思路&#xff1a;利用双指针i和…

synchronized 关键字

目录 背景过程历史概念实际应用方法1&#xff1a;放方法名前形成同步方法&#xff1b;方法2&#xff1a;使用同步块修改上面的例子&#xff1b; 应用方法锁住对象&#xff1a;锁住类&#xff1a; 总结 背景 学习并发&#xff0c;为解决并发带来的问题&#xff0c;引入synchron…

React Dva项目中模仿网络请求数据方法

我们都已经选择react了 那么自然是一个前后端分离的开发形式 至少我在公司中 大部分时候是前后端同时开发的 一般你在开发界面没有接口直接给你 但你可以和后端约定数据格式 然后在前端模拟数据 我们在自己的Dva项目中 在根目录下的 mock 目录下创建一个js文件 我这里叫 filmDa…

ES6 (js)

学习了很多vue的视频&#xff0c;还有nuxt的&#xff0c;还是不会。 还是要学ES6 本文的大部分出自小马老师的资料&#xff0c;还有曾大佬的文章 变量&#xff08;Let 和 const&#xff09; 在es6中&#xff0c;多用let 和const 来声明变量类型。因为var 会提前声明&#xff0…

flink cdc环境搭建

1.下载flink https://archive.apache.org/dist/flink/flink-1.12.2/ 2.修改flink-conf.yaml #根据自己电脑核数修改&#xff0c;这里我设置为4&#xff0c;因为系统分配了4核 jobmanager.rpc.address: localhost #主机名根据自己设定 taskmanager.numberOfTaskSlots: 4 3.下载…

mysql进阶2——prosysql实现mysql读写分离

文章目录 一、读写分离方案类型1.1 最简单的读写分离1.2 多个读组或写组的分离模式 二、案例2.1 初始化操作2.2 mysql主添加proxysql连接用户2.3 Proxysql添加连接mysql集群参数2.4 添加健康检测用户2.5 添加读写分离的路由规则2.6 验证 一、读写分离方案类型 基本了解&#xf…

【uniapp】更改富文本编辑器图片大小

代码块 //<view v-html"productDetails"></view><rich-text :nodes"productDetails"></rich-text>// 假设htmlContent字段是后台返回的富文本字段var htmlContent res.result.productDetailsconst regex new RegExp(<img, gi…

STM32MP157驱动开发——按键驱动(休眠与唤醒)

文章目录 “休眠-唤醒”机制&#xff1a;APP执行过程内核函数休眠函数唤醒函数 休眠与唤醒方式的按键驱动程序(stm32mp157)驱动程序框架button_test.cgpio_key_drv.cMakefile修改设备树文件编译测试 “休眠-唤醒”机制&#xff1a; 当应用程序必须等待某个事件发生&#xff0c…

爬虫001_Pip指令使用_包管理工具_pip的使用_和源的切换---python工作笔记019

scrapy是一个爬虫的框架 确认一下pip这个python中的包管理工具是否已经安装好了 python的环境变量配置完了以后,还需要配置一下pip的环境变量 把这个目录配置好,这个pip的环境变量的配置很简单不多说了. 我们用pip安装一下包,我们安装到上面这个路径里面,就是python的安装路…

Qt - .ui 文件的使用

文章目录 目录工具栏Dock Widget代码控制 ui添加资源添加文件 目录 子目录只能输入英文&#xff0c;想要显示中文&#xff0c;可以修改右下方表中的 text 属性&#xff1a; 工具栏 让工具栏共用 菜单栏的 new 和 open&#xff0c;只需将下方列表的控件&#xff0c;拖拽到工具栏…

【RS】基于规则的面向对象分类

ENVI使用最多的工具就是分类&#xff0c;这也是很多卫星影像的用途。在ENVI中有很多分类工具&#xff0c;如最基础的监督分类&#xff08;最大似然法、最小距离、支持向量机、随机森林&#xff09;、非监督分类&#xff08;K-means、IsoData&#xff09;&#xff0c;还有面向对…

安卓开发后台应用周期循环获取位置信息上报服务器

问题背景 最近有需求&#xff0c;在APP启动后&#xff0c;退到后台&#xff0c;还要能实现周期获取位置信息上报服务器&#xff0c;研究了一下实现方案。 问题分析 一、APP退到后台后网络请求实现 APP退到后台后&#xff0c;实现周期循环发送网络请求。目前尝试了两种方案是…

随笔--更改已经启动中的容器的配置文件

文章目录 docker 容器的配置信息地址修改文件映射 docker 容器的配置信息地址 # 一般在 sudo su cd /cd /var/lib/docker/containers/{容器id}/ # 查看容器的id,CONTAINER ID就是容器id的前部分 docker ps修改文件映射 进入容器的配置文件位置一般包含这些文件 # 先stop容器…