真爱,请置顶或星标

大家好,希望各位能怀着正直、严谨、专业的心态观看这篇文章。ヾ(๑╹◡╹)ノ"

接下来我们尝试用 Python 抓取天猫内衣销售数据,并分析得到中国女性普遍的罩杯数据、最受欢迎的内衣颜色是什么、评论的关键字。希望看完之后你能替你女朋友买上一件心怡的内衣。我们先看看分析得到的成果是怎样的?(讲的很详细,推荐跟着敲一遍)  

(买个内衣这么开心)

图片看不清楚的话,可以把图片单独拉到另一个窗口。这里是分析了一万条数据得出的结论,可能会有误差,但是还是希望单身的你们能找到 0.06% 那一批妹纸。下面我会详细介绍怎么抓取天猫内衣销售数据,存储、分析、展示。

  • 研究天猫网站Python入门到精通学习教程请加群

  • 抓取天猫评论数据

  • 存储、分析数据

  • 可视化 219539519零基础,进阶欢迎加入

研究天猫网站

我们随意进入一个商品的购买界面(能看到评论的那个界面),F12 开发者模式 -- Network 栏 -- 刷新下界面 -- 在如图的位置搜索 list_ 会看到一个 list_detail_rate.htm?itemId= ….

如下图:【单击】这个url 能看到返回的是一个 Json 数据 ,检查一下你会发现这串 Json 就是商品的评论数据 ['rateDetail']['rateList']

【双击】这个url 你会得到一个新界面,如图

看一下这个信息

这里的路径 就是获取评论数据的 url了。这个 URL 有很多参数你可以分析一下每个值都是干嘛的。

itemId 对应的是商品id, sellerId  对应的是店铺id,currentPage 是当前页。这里 sellerId  可以填任意值,不影响数据的获取。

抓取天猫评论数据

写一个抓取天猫评论数据的方法。getCommentDetail

# 获取商品评论数据def getCommentDetail(itemId,currentPage):    url = 'https://rate.tmall.com/list_detail_rate.htm?itemId=' + str(        itemId) + '&sellerId=2451699564&order=3&currentPage=' + str(currentPage) + '&append=0callback=jsonp336'    # itemId 产品id ;sellerId 店铺id 字段必须有值,但随意值就行    html = common.getUrlContent(url)  # 获取网页信息    # 删掉返回的多余信息    html = html.replace('jsonp128(','') #需要确定是不是 jsonp128    html = html.replace(')','')    html = html.replace('false','"false"')    html = html.replace('true','"true"')    # 将string 转换为字典对象    tmalljson = json.loads(html)    return tmalljson

这里需要注意的是 jsonp128 这个值需要你自己看一下,你那边跟我这个应该是不同的。

在上面的方法里有两个变量,itemId 和 currentPage 这两个值我们动态来控制,所以我们需要获得 一批 商品id号 和 评论的最大页数 用来遍历。

写个获取商品评论最大页数的方法 getLastPage

# 获取商品评论最大页数def getLastPage(itemId):    tmalljson = getCommentDetail(itemId,1)    return tmalljson['rateDetail']['paginator']['lastPage'] #最大页数

那现在怎么获取 产品的id 列表呢?我们可以在天猫中搜索商品关键字 用开发者模式观察

这里观察一下这个页面的元素分布,很容易就发现了 商品的id 信息,当然你可以想办法确认一下。

现在就写个 获取商品id 的方法 getProductIdList

# 获取商品iddef getProductIdList():    url = 'https://list.tmall.com/search_product.htm?q=内衣' # q参数 是查询的关键字    html = common.getUrlContent(url)  # 获取网页信息    soup = BeautifulSoup(html,'html.parser')    idList = []    # 用Beautiful Soup提取商品页面中所有的商品ID    productList = soup.find_all('div', {'class': 'product'})    for product in productList:        idList.append(product['data-id'])    return idList

现在所有的基本要求都有了,是时候把他们组合起来。

在 main 方法中写剩下的组装部分

if __name__ == '__main__':    productIdList = getProductIdList() #获取商品id    initial = 0    while initial < len(productIdList) - 30:  # 总共有60个商品,我只取了前30个        try:            itemId = productIdList[initial]            print('----------', itemId, '------------')            maxPage = getLastPage(itemId) #获取商品评论最大页数            num = 1            while num <= maxPage and num < 20: #每个商品的评论我最多取20 页,每页有20条评论,也就是每个商品最多只取 400 个评论                try:                    # 抓取某个商品的某页评论数据                    tmalljson = getCommentDetail(itemId, num)                    rateList = tmalljson['rateDetail']['rateList']                    commentList = []                    n = 0                    while (n < len(rateList)):                        comment = []                        # 商品描述                        colorSize = rateList[n]['auctionSku']                        m = re.split('[:;]', colorSize)                        rateContent = rateList[n]['rateContent']                        dtime = rateList[n]['rateDate']                        comment.append(m[1])                        comment.append(m[3])                        comment.append('天猫')                        comment.append(rateContent)                        comment.append(dtime)                        commentList.append(comment)                        n += 1                    print(num)                    sql = "insert into bras(bra_id, bra_color, bra_size, resource, comment, comment_time)  value(null, %s, %s, %s, %s, %s)"                    common.patchInsertData(sql, commentList) # mysql操作的批量插入                    num += 1                except Exception as e:                    num += 1                    print(e)                    continue            initial += 1        except Exception as e:            print(e)

所有的代码就这样完成了,我现在把 common.py 的代码,还有 tmallbra.py 的代码都贴出来

# -*- coding:utf-8 -*-# Author: zwwimport requestsimport timeimport randomimport socketimport http.clientimport pymysqlimport csv# 封装requestsclass Common(object):    def getUrlContent(self, url, data=None):        header = {            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',            'Accept-Encoding': 'gzip, deflate, br',            'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',            'user-agent': "User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36",            'cache-control': 'max-age=0'        }  # request 的请求头        timeout = random.choice(range(80, 180))        while True:            try:                rep = requests.get(url, headers=header, timeout=timeout)  # 请求url地址,获得返回 response 信息                # rep.encoding = 'utf-8'                break            except socket.timeout as e:  # 以下都是异常处理                print('3:', e)                time.sleep(random.choice(range(8, 15)))            except socket.error as e:                print('4:', e)                time.sleep(random.choice(range(20, 60)))            except http.client.BadStatusLine as e:                print('5:', e)                time.sleep(random.choice(range(30, 80)))            except http.client.IncompleteRead as e:                print('6:', e)                time.sleep(random.choice(range(5, 15)))        print('request success')        return rep.text  # 返回的 Html 全文    def writeData(self, data, url):        with open(url, 'a', errors='ignore', newline='') as f:            f_csv = csv.writer(f)            f_csv.writerows(data)        print('write_csv success')    def queryData(self, sql):        db = pymysql.connect("localhost", "zww", "960128", "test")        cursor = db.cursor()        results = []        try:            cursor.execute(sql)    #执行查询语句            results = cursor.fetchall()        except Exception as e:            print('查询时发生异常' + e)            # 如果发生错误则回滚            db.rollback()        # 关闭数据库连接        db.close()        return results        print('insert data success')    def insertData(self, sql):        # 打开数据库连接        db = pymysql.connect("localhost", "zww", "000000", "zwwdb")        # 使用 cursor() 方法创建一个游标对象 cursor        cursor = db.cursor()        try:            # sql = "INSERT INTO WEATHER(w_id, w_date, w_detail, w_temperature) VALUES (null, '%s','%s','%s')" % (data[0], data[1], data[2])            cursor.execute(sql)    #单条数据写入            # 提交到数据库执行            db.commit()        except Exception as e:            print('插入时发生异常' + e)            # 如果发生错误则回滚            db.rollback()        # 关闭数据库连接        db.close()        print('insert data success')    def patchInsertData(self, sql, datas):        # 打开数据库连接        db = pymysql.connect("localhost", "zww", "960128", "test")        # 使用 cursor() 方法创建一个游标对象 cursor        cursor = db.cursor()        try:            # 批量插入数据            # cursor.executemany('insert into WEATHER(w_id, w_date, w_detail, w_temperature_low, w_temperature_high) value(null, %s,%s,%s,%s)',datas)            cursor.executemany(sql, datas)            # 提交到数据库执行            db.commit()        except Exception as e:            print('插入时发生异常' + e)            # 如果发生错误则回滚            db.rollback()        # 关闭数据库连接        db.close()        print('insert data success')

上面需要注意,数据库的配置。

# -*- coding:utf-8 -*-# Author: zwwfrom Include.commons.common import Commonfrom bs4 import BeautifulSoupimport jsonimport reimport pymysqlcommon = Common()# 获取商品iddef getProductIdList():    url = 'https://list.tmall.com/search_product.htm?q=内衣' # q参数 是查询的关键字,这要改变一下查询值,就可以抓取任意你想知道的数据    html = common.getUrlContent(url)  # 获取网页信息    soup = BeautifulSoup(html,'html.parser')    idList = []    # 用Beautiful Soup提取商品页面中所有的商品ID    productList = soup.find_all('div', {'class': 'product'})    for product in productList:        idList.append(product['data-id'])    return idList# 获取商品评论数据def getCommentDetail(itemId,currentPage):    url = 'https://rate.tmall.com/list_detail_rate.htm?itemId=' + str(        itemId) + '&sellerId=2451699564&order=3&currentPage=' + str(currentPage) + '&append=0callback=jsonp336'    # itemId 产品id ;sellerId 店铺id 字段必须有值,但随意值就行    html = common.getUrlContent(url)  # 获取网页信息    # 删掉返回的多余信息    html = html.replace('jsonp128(','') #需要确定是不是 jsonp128    html = html.replace(')','')    html = html.replace('false','"false"')    html = html.replace('true','"true"')    # 将string 转换为字典对象    tmalljson = json.loads(html)    return tmalljson# 获取商品评论最大页数def getLastPage(itemId):    tmalljson = getCommentDetail(itemId,1)    return tmalljson['rateDetail']['paginator']['lastPage'] #最大页数if __name__ == '__main__':    productIdList = getProductIdList() #获取商品id    initial = 0    while initial < len(productIdList) - 30:  # 总共有60个商品,我只取了前30个        try:            itemId = productIdList[initial]            print('----------', itemId, '------------')            maxPage = getLastPage(itemId) #获取商品评论最大页数            num = 1            while num <= maxPage and num < 20: #每个商品的评论我最多取20 页,每页有20条评论,也就是每个商品最多只取 400 个评论                try:                    # 抓取某个商品的某页评论数据                    tmalljson = getCommentDetail(itemId, num)                    rateList = tmalljson['rateDetail']['rateList']                    commentList = []                    n = 0                    while (n < len(rateList)):                        comment = []                        # 商品描述                        colorSize = rateList[n]['auctionSku']                        m = re.split('[:;]', colorSize)                        rateContent = rateList[n]['rateContent']                        dtime = rateList[n]['rateDate']                        comment.append(m[1])                        comment.append(m[3])                        comment.append('天猫')                        comment.append(rateContent)                        comment.append(dtime)                        commentList.append(comment)                        n += 1                    print(num)                    sql = "insert into bras(bra_id, bra_color, bra_size, resource, comment, comment_time)  value(null, %s, %s, %s, %s, %s)"                    common.patchInsertData(sql, commentList) # mysql操作的批量插入                    num += 1                except Exception as e:                    num += 1                    print(e)                    continue            initial += 1        except Exception as e:            print(e)

存储、分析数据

所有的代码都有了,就差数据库的建立了。我这里用的是 MySql 数据库。

CREATE TABLE `bra` (`bra_id`  int(11) NOT NULL AUTO_INCREMENT COMMENT 'id' ,`bra_color`  varchar(25) NULL COMMENT '颜色' ,`bra_size`  varchar(25) NULL COMMENT '罩杯' ,`resource`  varchar(25) NULL COMMENT '数据来源' ,`comment`  varchar(500) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '评论' ,`comment_time`  datetime NULL COMMENT '评论时间' ,PRIMARY KEY (`bra_id`)) character set utf8;

这里有两个地方需要注意, comment 评论字段需要设置编码格式为 utf8mb4  ,因为可能有表情文字。还有表需要设置为 utf8 编码,不然存不了中文。

建好了表,就可以完整执行代码了。(这里的执行可能需要点时间,可以做成多线程的方式)。看一下执行完之后,数据库有没有数据。

数据是有了,但是有些我们多余的文字描述,我们可以稍微整理一下。

update bra set bra_color = REPLACE(bra_color,'2B6521-无钢圈4-','');update bra set bra_color = REPLACE(bra_color,'-1','');update bra set bra_color = REPLACE(bra_color,'5','');update bra set bra_size = substr(bra_size,1,3);

这里需要根据自己实际情况来修改。如果数据整理的差不多了,我们可以分析一下数据库的信息。

select 'A罩杯' as 罩杯, CONCAT(ROUND(COUNT(*)/(select count(*) from bra) * 100, 2) , "%") as 比例, COUNT(*) as 销量  from bra where bra_size like '%A'union all select 'B罩杯' as 罩杯, CONCAT(ROUND(COUNT(*)/(select count(*) from bra) * 100, 2) , "%") as 比例, COUNT(*) as 销量  from bra where bra_size like '%B'union all select 'C罩杯' as 罩杯, CONCAT(ROUND(COUNT(*)/(select count(*) from bra) * 100, 2) , "%") as 比例, COUNT(*) as 销量  from bra where bra_size like '%C'union all select 'D罩杯' as 罩杯, CONCAT(ROUND(COUNT(*)/(select count(*) from bra) * 100, 2) , "%") as 比例, COUNT(*) as 销量  from bra where bra_size like '%D'union all select 'E罩杯' as 罩杯, CONCAT(ROUND(COUNT(*)/(select count(*) from bra) * 100, 2) , "%") as 比例, COUNT(*) as 销量  from bra where bra_size like '%E'union all select 'F罩杯' as 罩杯, CONCAT(ROUND(COUNT(*)/(select count(*) from bra) * 100, 2) , "%") as 比例, COUNT(*) as 销量  from bra where bra_size like '%F'union all select 'G罩杯' as 罩杯, CONCAT(ROUND(COUNT(*)/(select count(*) from bra) * 100, 2) , "%") as 比例, COUNT(*) as 销量  from bra where bra_size like '%G'union all select 'H罩杯' as 罩杯, CONCAT(ROUND(COUNT(*)/(select count(*) from bra) * 100, 2) , "%") as 比例, COUNT(*) as 销量  from bra where bra_size like '%H'order by 销量 desc;

 

  (想知道是哪6位小姐姐买的 G       (~ ̄▽ ̄)~ )

数据可视化

数据的展示,我用了是 mycharts 模块,如果不了解的可以去学习一下http://pyecharts.org/#/zh-cn/prepare

这里我就不细说了,直接贴代码看

# encoding: utf-8# author zwwfrom pyecharts import Piefrom Include.commons.common import Commonif __name__ == '__main__':    common = Common()    results = common.queryData("""select count(*) from bra where bra_size like '%A'             union all select count(*) from bra where bra_size like '%B'             union all select count(*) from bra where bra_size like '%C'             union all select count(*) from bra where bra_size like '%D'             union all select count(*) from bra where bra_size like '%E'             union all select count(*) from bra where bra_size like '%F'             union all select count(*) from bra where bra_size like '%G'""")  # 获取每个罩杯数量    attr = ["A罩杯", 'G罩杯', "B罩杯", "C罩杯", "D罩杯", "E罩杯", "F罩杯"]    v1 = [results[0][0], results[6][0], results[1][0], results[2][0], results[3][0], results[4][0], results[5][0]]    pie = Pie("内衣罩杯", width=1300, height=620)    pie.add("", attr, v1, is_label_show=True)    pie.render('size.html')    print('success')    results = common.queryData("""select count(*) from bra where bra_color like '%肤%'         union all select count(*) from bra where bra_color like '%灰%'         union all select count(*) from bra where bra_color like '%黑%'         union all select count(*) from bra where bra_color like '%蓝%'         union all select count(*) from bra where bra_color like '%粉%'         union all select count(*) from bra where bra_color like '%红%'         union all select count(*) from bra where bra_color like '%紫%'          union all select count(*) from bra where bra_color like '%绿%'         union all select count(*) from bra where bra_color like '%白%'         union all select count(*) from bra where bra_color like '%褐%'         union all select count(*) from bra where bra_color like '%黄%' """)  # 获取每个罩杯数量    attr = ["肤色", '灰色', "黑色", "蓝色", "粉色", "红色", "紫色", '绿色', "白色", "褐色", "黄色"]    v1 = [results[0][0], results[1][0], results[2][0], results[3][0], results[4][0], results[5][0], results[6][0], results[7][0], results[8][0], results[9][0], results[10][0]]    pieColor = Pie("内衣颜色", width=1300, height=620)    pieColor.add("", attr, v1, is_label_show=True)    pieColor.render('color.html')    print('success')

这一章就到这里了,该知道的你也知道了,不该知道的你也知道了。

为了给女朋友买件心怡内衣,我用Python爬虫了天猫内衣售卖数据的更多相关文章

  1. 【Python】动手分析天猫内衣售卖数据,得到你想知道的信息

    大家好,希望各位能怀着正直.严谨.专业的心态观看这篇文章.ヾ(๑╹◡╹)ノ" 接下来我们尝试用 Python 抓取天猫内衣销售数据,并分析得到中国女性普遍的罩杯数据.最受欢迎的内衣颜色是什么 ...

  2. 小白学 Python 爬虫(26):为啥上海二手房你都买不起

    人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...

  3. [控件] 心形加载的view

    心形加载的view 效果: 素材图片: 源码: StarView.h 与 StarView.m // // StarView.h // Star // // Created by XianMingYo ...

  4. 被女朋友三番五次拉黑后,我用 Python 写了个“舔狗”必备神器

    在一个阳光明媚的周日,我打开窗户呼吸了一口新鲜空气.阳光灿烂,岁月静好,又是一个约女朋友出去爬山吃饭看电影的好日子. 想到女朋友的大眼睛,我脸上不禁洋溢起了幸福的微笑.打开微信,给女朋友发出去一个美好 ...

  5. [Python爬虫] 之六:Selenium 常用控件用法

    Selenium 常用控件用法 1.文本框 上图中,如何定位搜索文本框,并输入搜索内容进行搜索 首先:利用方法 find_element_by_xpath定位元素:inputElements = se ...

  6. 火车票买不到?看我用python监控票源

    同事说最近火车票难买,我就帮他用个脚本监控 一下. 最近高铁票比较难买,还有什么候补.要不停的刷,才有时候可以捡漏.有时候明明候补了,到快开车告诉你余票不足,候补失败. 凡事预则立,我打算写个脚本提前 ...

  7. 过去,我买漫画看;现在,我用Python爬虫来看

    原标题:运用Python多线程爬虫下载漫画 前言: 以前,我都是买漫画书看的,那个时候没有电脑.今天,我到网上看了一下,发现网上提供漫画看,但是时时需要网络啊!为什么不将它下载下来呢!  1.怎样实现 ...

  8. GridControl控件添加按钮列及在按钮Click事件中得到行数据 zt

    在GridControl中添加按钮列的步骤如下: 1. 把列的ColumnEdit属性设置为RepositoryItemButtonEdit 2. 把TextEditStyle属性设置为HideTex ...

  9. 首次加载进来DEV控件列表第一行颜色总是不对,后台代码显示的数据正确

    1:行改变的颜色正确的颜色: 1.1颜色效果如下图: 1.2:设置行改变颜色: 2:结果首次加载第一行颜色为: 3:解决方案: 3.1 :Views-->OptionsSelection --& ...

随机推荐

  1. js获取一个月的天数

    在使用其他语言获取每月天数的时候,一般都是存储到一个数组中进行获取,但是如果是二月份的话就需要首先判断是否闰年,再确定是28还是29了. js可以通过Date对象很方便的获取到每月的天数,在初始化Da ...

  2. Kubernetes pod 状态

    CrashLoopBackOff: 容器退出,kubelet正在将它重启 InvalidImageName: 无法解析镜像名称 ImageInspectError: 无法校验镜像 ErrImageNe ...

  3. 致初学者(二): HDU 2014~ 2032题解

    下面继续给出HDU 2014~2032的AC程序,供大家参考.2014~2032这19道题就被归结为“C语言程序设计练习(三) ”~“C语言程序设计练习(五) ”. HDU 2014:青年歌手大奖赛_ ...

  4. Java连载30-方法重载、方法递归

    一.方法重载 1.又被称为overload 2.方法重载使用场景 功能类似的时候,尽可能仍方法名相同(但是功能不同或者不相似的时候,方法名尽量不同) 3.什么条件满足之后,可以构成方法重载 (1)在同 ...

  5. sql 单表distinct/多表group by查询去除重复记录

    单表distinct 多表group by group by 必须放在 order by 和 limit之前,不然会报错 下面先来看看例子: table   id name   1 a   2 b   ...

  6. Python集训营45天—Day03

    目录 1. 分支结构 1.1 初步介绍 1.2 使用案例 1.3 练习 2.循环结构 1.1 初步介绍 1.2 使用案例 1. 分支结构 1.1 初步介绍 至今,我们所写的Python代码都是顺序执行 ...

  7. Winform中跨窗体设置Zedgraph的属性并刷新曲线图

    场景 在使用ZedGraph时,经常有图形选项功能,设置曲线图相关属性后, 点击保存会设置另一个窗体的属性并刷新图. 效果 实现 在设置图形的选项的类中,声明委托和事件 //委托的定义 public ...

  8. C#中使用StreamReader实现文本文件的读取与写入

    场景 实现一个 TextReader,使其以一种特定的编码从字节流中读取字符. 关注公众号霸道的程序猿获取编程相关电子书.教程推送与免费下载. 大量编程视频教程:https://space.bilib ...

  9. flink有什么优势值得大家这么热衷

    flink 通过实现了 Google Dataflow 流式计算模型实现了高吞吐.低延迟.高性能兼具实时流式计算框架. 同时 flink 支持高度容错的状态管理,防止状态在计算过程中因为系统异常而丢失 ...

  10. [LeetCode] 由 “分形" 所想

    分形思想和递归思想有区别么? 一.简单例子 函数调用自己,简化了理解逻辑,但其他到处都是问题. #%% def listsum(numList): if len(numList) == 1: retu ...