淘宝商品数据爬取并分析数据
Posted Packbacker_s
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了淘宝商品数据爬取并分析数据相关的知识,希望对你有一定的参考价值。
一、抓取数据
1、抓取数据的意义
对电商来说,抓取某些数据,再进行分析,可以有效地反映出数据在某个区间内变化情况。数据受某些因素而发生巨大的影响,也可以借助分析的数据来规划相关项目的后续发展。因此,如果能利用网页爬取数据技术获取数据并对各种数据进行统计分析,对后续淘宝的发展具有指导意义。
2、抓取的内容
包括:商品名称title、商品价格price、付款人数deal,店铺名称shop、店铺地址location、商品的详情页detail_url。
3、实现内容
1、开打淘宝网站,输入搜索内容“word”查找商品
2、再解决登录问题(登录时解决网站对selenium的判别,修改浏览器的内部属性,否则被识别出有selenium,需要进行滑动登陆验证。但是在运行时,你手动地去进行滑动登录也是会判别出存在selenium的,进而登陆不上去)
3、对查找商品在控制台上输出
4、具体实现代码
4.1所需模块
from selenium import webdriver
import time
import random
首先的话,我们需要导入一些模块,比如第三方模块selenium,大家如果发生报错的话,就需要额外安装了,安装selenium模块有2个方法:
1、在pycharm的terminal控制台命令行中输入:pip install selenium
2、在win+r中的cmd里输入:pip install selenium
这两个方法都是可以的。
import time
import random
这两个的话,我们则是用来设置随机时间的,在抓取到数据之前,我们需要点击搜索框、搜索一些按键。我们需要模拟人为的操作时间,否则的话很可能操作失败了,我们随机地等待1-3秒的时间。
4.2创建chrome浏览器,打开淘宝网
在关于创建浏览器的话,首选是chrome浏览器,调出开发者模式太方便了!!!,火狐也是可以的,但首选首选首选chrome,因为我真的没用过火狐,哈哈哈哈哈哈
然后使用driver.get()方法,往内部传一个地址,我们就用淘宝网的地址。我们也就打开了下面的所示淘宝的网页界面。
driver = webdriver.Chrome() # 创建谷歌浏览器
# TODO 执行浏览器操作
driver.get('https://www.taobao.com/')
driver.implicitly_wait(10) # 智能化等待方法
driver.maximize_window() # 最大化
4.3Xpath解析路径
我们要在淘宝网的搜索框中输入我们的商品,还要点搜索按钮,进而还需要登录(需要用户名、密码)。这都需要我们在网页上定位这些搜索框、搜索按钮、用户名框、密码框、登录按钮。所以打开淘宝网页的开发者模式,找到搜索框、搜索按钮、用户名框、密码框、登录按钮的xpath。
我们利用find_element_by_xpath()这个函数来解析对应的xpath
设置等待的时间,模拟人为操作
driver.find_element_by_xpath('//*[@id="q"]').send_keys(word)
time.sleep(random.randint(1, 3))
driver.find_element_by_xpath('//*[@id="J_TSearchForm"]/div[1]/button').click()
time.sleep(random.randint(1, 3))
开发者模式:
首先我们定位到搜索框,就在开发者模式的Elements下,copy --> copy xpath。复制到我们的find_element_by_xpath()函数中,其他的搜索按钮、用户名框、密码框、登录按钮也是这样找。
4.4 搜索商品关键字
在淘宝网上,根据我们所需要爬取的商品信息,在搜索框中搜索爬取的商品,比如说 帽子。
word = input('请输入要搜索的关键字:')
# TODO 创建浏览器
driver = webdriver.Chrome()
# TODO 执行浏览器操作
driver.get('https://www.taobao.com/') # 传一个地址
driver.implicitly_wait(10) # 智能化等待方法
driver.maximize_window() # 最大化
driver.find_element_by_xpath('//*[@id="q"]').send_keys(word) #
time.sleep(random.randint(1, 3))
driver.find_element_by_xpath('//*[@id="J_TSearchForm"]/div[1]/button').click()
time.sleep(random.randint(1, 3))
在搜索之后就出现一个登陆的界面,我们再根据4.3xpath解析路径的方法将我们的用户名,密码传进去,再进行登录。
代码如下:
"""用户账号及密码登录"""
driver.find_element_by_xpath('//*[@id="fm-login-id"]').send_keys('xxxxxxx') # TODO 输入用户名
time.sleep(random.randint(1, 3))
driver.find_element_by_xpath('//*[@id="fm-login-password"]').send_keys('xxxxxxxx') # TODO 输入密码
time.sleep(random.randint(1, 3))
driver.find_element_by_xpath('//*[@id="login-form"]/div[4]/button').click()
time.sleep(random.randint(1, 3))
不过此时会遇到一个问题:登陆的时候需要我们进行滑动验证
这是因为淘宝网检测出了selenium这个东西,尽管你人为地去滑动,但还是会登陆失败。
所以我们在创建出浏览器之后,随即改变浏览器内部的一些属性,可以网站避免检测出selenium的存在,就不需要我们进行滑动登录的验证了。
# 修改了浏览器的内部属性,跳过了登录的滑动验证
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",
"source": """Object.defineProperty(navigator, 'webdriver', get: () => undefined)""")
4.5获取爬取商品具体信息
解析获取商品名称title、商品价格price、付款人数deal,店铺名称shop、店铺地址location、商品的详情页detail_url的数据
这时候我们需要借助一个插件:xpath helper 十分好用,可以写我们xpath的语法,来帮助我们定位商品的具体信息。
例:这一页的48个商品名称
下载地址:
链接:https://pan.baidu.com/s/1iCEbjnpa8dhTDScIhkvbZA
提取码:1uv9
找到第一个商品,找到商品列表,每个商品列表里面都有该商品的具体信息,比如商品名称、商品价格、付款人数,店铺名称、店铺地址、等等等的数据
我们要获取所有的div标签divs,然后再遍历divs去获取所需要的商品具体信息
具体代码:
def parse_data():
# 多个商品数据解析
divs = driver.find_elements_by_xpath('//div[@class="grid g-clearfix"]/div/div') # 获取所有的div标签
for div in divs:
title = div.find_element_by_xpath('.//div[@class="row row-2 title"]/a').text # 商品名字
price = div.find_element_by_xpath('.//strong').text + '元' # 商品价格
deal = div.find_element_by_xpath('.//div[@class="deal-cnt"]').text # 付款人数
shop = div.find_element_by_xpath('.//div[@class="shop"]/a/span[2]').text # 店铺名称
location = div.find_element_by_xpath('.//div[@class="location"]').text # 店铺地点
detail_url = div.find_element_by_xpath('.//div[@class="row row-2 title"]/a').get_attribute('href') # 详情页地址
print(title, price, deal, shop, location, detail_url)
爬取第一页和第二页的商品信息,一页爬取完之后便点击下一页
for page in range(0, 2):
print(f'-----------------正在爬取第page + 1页-----------------')
# TODO 调用商品解析的函数
parse_data()
driver.find_element_by_xpath('//li[@class="item next"]/a[@class="J_Ajax num icon-tag"]').click()
time.sleep(random.randint(2, 3))
5、完整代码及结果
完整代码如下:
from selenium import webdriver
import time
import random
def parse_data():
divs = driver.find_elements_by_xpath('//div[@class="grid g-clearfix"]/div/div') # 所有的div标签
for div in divs:
test = div.find_element_by_xpath('.//div[@class="row row-2 title"]/a').text # 商品名字
price = div.find_element_by_xpath('.//strong').text + '元' # 商品价格
deal = div.find_element_by_xpath('.//div[@class="deal-cnt"]').text # 付款人数
name = div.find_element_by_xpath('.//div[@class="shop"]/a/span[2]').text # 店铺名称
location = div.find_element_by_xpath('.//div[@class="location"]').text # 店铺地点
detail_url = div.find_element_by_xpath('.//div[@class="row row-2 title"]/a').get_attribute('href') # 详情页地址
print(test, price, deal, name, location, detail_url)
if __name__ == '__main__':
word = input('请输入要搜索的关键字:')
# TODO 1、创建浏览器
driver = webdriver.Chrome()
# TODO 2、修改了浏览器的内部属性,跳过了登录的滑动验证
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",
"source": """Object.defineProperty(navigator, 'webdriver', get: () => undefined)""")
# TODO 3、执行浏览器操作
driver.get('https://www.taobao.com/')
driver.implicitly_wait(10) # 智能化等待方法
driver.maximize_window() # 最大化
driver.find_element_by_xpath('//*[@id="q"]').send_keys(word)
time.sleep(random.randint(1, 3))
driver.find_element_by_xpath('//*[@id="J_TSearchForm"]/div[1]/button').click()
time.sleep(random.randint(1, 3))
"""用户账号及密码登录"""
driver.find_element_by_xpath('//*[@id="fm-login-id"]').send_keys('xxxxxx') # TODO 输入用户名
time.sleep(random.randint(1, 3))
driver.find_element_by_xpath('//*[@id="fm-login-password"]').send_keys('xxxxxxx') # TODO 输入密码
time.sleep(random.randint(1, 3))
driver.find_element_by_xpath('//*[@id="login-form"]/div[4]/button').click()
time.sleep(random.randint(1, 3))
for page in range(0, 2):
print(f'-----------------正在爬取第page + 1页-----------------')
# TODO 调用商品解析的函数
parse_data()
driver.find_element_by_xpath('//li[@class="item next"]/a[@class="J_Ajax num icon-tag"]').click()
time.sleep(random.randint(2, 3))
爬取的结果如图:
二、存入数据库
from pymysql import * # 连接MySQL数据库
import pymysql
- 连接我们本机的数据库
- 接着创建游标对象
- 执行sql语句,将数据存入数据库表information中
(注意:在sql语句里,“不要用%或者+操作符来拼接SQL语句,应该使用占位符”,因为我使用了%拼接在运行的时候出错了,找了百度解决了这个问题)
mysql_obj = connect(host='127.0.0.1', user='root', password='xxxxxxxx', database='webcrawlers', port=3306,
charset='utf8mb4')
# 创建游标
cur_obj = mysql_obj.cursor()
# TODO 就是不要用%或者+操作符来拼接SQL语句,应该使用占位符
cur_obj.execute(
'insert into Information(id, name_product, price_product, number_purchaser, name_store, address_store, detail_url) values(0, ("%s"), ("%s"), ("%s"), ("%s"), ("%s"), ("%s")) ' , (
title, price, deal, shop, location, detail_url))
mysql_obj.commit()
cur_obj.close()
mysql_obj.close()
三、数据库数据导入csv文件并建模分析
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
import pymysql
在将数据库导入csv文件,借助了这个博客python把mysql数据库中的数据表写入csv文件_程序员 小明的博客-CSDN博客
"""参考此博客https://blog.csdn.net/weixin_42304193/article/details/89607394
将数据库数据导入csv文件
"""
class Test_myqsl(object):
# 运行数据库和建立游标对象
def __init__(self):
self.connect = pymysql.connect(host="127.0.0.1", port=3306, user="root", password="xxxxxxx", database="webcrawlers",
charset="utf8mb4")
# 返回一个cursor对象,也就是游标对象
self.cursor = self.connect.cursor(cursor=pymysql.cursors.DictCursor)
# 关闭数据库和游标对象
def __del__(self):
self.connect.close()
self.cursor.close()
def write(self):
# 将数据转化成DataFrame数据格式
data = pd.DataFrame(self.read())
# 把id设置成行索引
data_1 = data.set_index("id", drop=True)
# 写写入数据数据
pd.DataFrame.to_csv(data_1, "e:/python1/taobaodatatest.csv", encoding="gbk")
print("写入成功")
def read(self):
# 读取数据库的所有数据
data = self.cursor.execute("""select * from information""")
field_2 = self.cursor.fetchall()
# pprint(field_2)
return field_2
# 封装
def main():
write = Test_myqsl()
write.write()
此时,我们在e盘中的python1文件中,就有了taobaodatatest.csv这个文件。里面的数据是由webcrawlers数据库information这个表导入的。
在我们进行数据分析之前,我们要拿到商品的价格price_product、和购买人数number_purchase
这里面的数据包含了一些无用符号,比如说' '、万、+、人付款、元。我们需要它的数据进行分析。所以我们把这些符号处理一下,拿到我们所需要的数据。
# TODO 对csv文件进行符号、文字的替换
f = open('E:/python1/taobaodatatest.csv', encoding='gbk')
content_f = f.read()
with open('E:/python1/taobaodatatest.csv', 'w', encoding='gbk') as f1:
t = content_f.replace("'", ' ')
f1.write(t)
f.close()
f = open('E:/python1/taobaodatatest.csv', encoding='gbk')
content_f = f.read()
with open('E:/python1/taobaodatatest.csv', 'w', encoding='gbk') as f2:
g = content_f.replace('万', '0000')
f2.write(g)
f.close()
f = open('E:/python1/taobaodatatest.csv', encoding='gbk')
content_f = f.read()
with open('E:/python1/taobaodatatest.csv', 'w', encoding='gbk') as f3:
h = content_f.replace('+', '')
f3.write(h)
f.close()
f = open('E:/python1/taobaodatatest.csv', encoding='gbk')
content_f = f.read()
with open('E:/python1/taobaodatatest.csv', 'w', encoding='gbk') as f4:
j = content_f.replace('人付款', '')
f4.write(j)
f.close()
f = open('E:/python1/taobaodatatest.csv', encoding='gbk')
content_f = f.read()
with open('E:/python1/taobaodatatest.csv', 'w', encoding='gbk') as f5:
k = content_f.replace('元', '')
f5.write(k)
f.close()
将taobaodatatest.csv文件的特殊符号处理完之后,进行数据分析、建模
# TODO 1.分析商品价格对销量的影响
tbdata = pd.read_csv('e:/python1/taobaodatatest.csv', encoding='gbk')
sns.set(style="darkgrid")
sns.jointplot(x="price_product", y='number_purchaser', data=tbdata, kind='scatter', color='purple')
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.title('商品价格对销量的影响', loc='right')
plt.show()
# TODO 2.分析商品价格对销售总额的影响
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
tbdata['GMV'] = (tbdata['price_product']) * (tbdata['number_purchaser'])
sns.regplot(x="price_product", y="GMV", data=tbdata, color='purple')
plt.title('商品价格对销售总额的影响')
plt.show()
# TODO 3.分析不同省份的店铺数量分布
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.figure(figsize=(8, 4))
province = tbdata['address_store']
province.value_counts().plot(kind='bar', color='purple')
plt.xticks(rotation=90)
plt.xlabel('省份')
plt.ylabel('店铺数量')
plt.title('不同省份的店铺数量分布')
plt.show()
# TODO 4.直观地表示价格、省份、销量三者之间的关系(这里采用三维绘图表示三者关系)
x, y = np.mgrid[-2:2:20j, -2:2:20j]
z = x * np.exp(-x ** 2 - y ** 2)
ax = plt.subplot(111, projection='3d')
ax.plot_surface(x, y, z, rstride=2, cstride=1, cmap=plt.cm.Blues_r)
ax.set_xlabel("price_product")
ax.set_ylabel("address_store")
ax.set_zlabel("number_purchaser")
plt.title('价格、省份、销量三者之间的关系')
plt.show()
在程序运行的时候,在最后的数据建模分析的时候出现了错误:
TypeError: cannot convert the series to <class 'int'>这个错误。网上查了python报TypeError: cannot convert the series to <class 'float'> - 极客分享
这篇中说:可能是出现了空值,这个空值也是很特殊,既不是null也不是none。然后我翻了我的数据库,发现爬取的数据,极个别商品没有商品价格、商品没有购买人数。这就导致我在计算总销售额的时候出现了这个错误
所以在对爬取数据存入数据库的时候,对xpath解析得到的:商品价格price、购买人数deal进行判定:当他们是 '' 的时候,我赋值一个0给它们。
if price == '':
price = 0
if deal == '':
deal = 0
此时爬取的数据进行分析结果如图:
表哥用Python爬取数千条淘宝商品数据后,发现淘宝这些潜规则!
本文记录了笔者用 Python 爬取淘宝某商品的全过程,并对商品数据进行了挖掘与分析,最终得出结论。
项目内容
-
本案例选择商品类目:沙发。
-
数量:共 100 页 4400 个商品。
-
筛选条件:天猫、销量从高到低、价格 500 元以上。
项目目的
-
对商品标题进行文本分析,词云可视化
-
不同关键词 word 对应的 sales 的统计分析
-
商品的价格分布情况分析
-
商品的销量分布情况分析
-
不同价格区间的商品的平均销量分布
-
商品价格对销量的影响分析
-
商品价格对销售额的影响分析
-
不同省份或城市的商品数量分布
-
不同省份的商品平均销量分布
注:本项目仅以以上几项分析为例。
项目步骤
-
数据采集:Python 爬取淘宝网商品数据
-
对数据进行清洗和处理
-
文本分析:jieba 分词、wordcloud 可视化
-
数据柱形图可视化:barh
-
数据直方图可视化:hist
-
数据散点图可视化:scatter
-
数据回归分析可视化:regplot
工具&模块
-
工具:本案例代码编辑工具 Anaconda 的 Spyder。
-
模块:requests、retrying、missingno、jieba、matplotlib、wordcloud、imread、seaborn 等。
爬取数据
因淘宝网是反爬虫的,虽然使用多线程、修改 headers 参数,但仍然不能保证每次 100% 爬取,所以我增加了循环爬取,每次循环爬取未爬取成功的页 ,直至所有页爬取成功停止。
说明:淘宝商品页为 JSON 格式,这里使用正则表达式进行解析。
代码如下:
数据清洗、处理
数据清洗、处理这个步骤也可以在 Excel 中完成,再读入数据。
代码如下:
说明:根据需求,本案例中只取了 item_loc,raw_title,view_price,view_sales 这 4 列数据,主要对区域、标题、价格、销量进行分析。
代码如下:
数据挖掘与分析
对 raw_title 列标题进行文本分析
使用结巴分词器,安装模块 pip install jieba:
对 title_s(list of list 格式)中的每个 list 的元素(str)进行过滤,剔除不需要的词语,即把停用词表 stopwords 中有的词语都剔除掉:
因为下面要统计每个词语的个数,所以为了准确性,这里对过滤后的数据 title_clean 中的每个 list 的元素进行去重,即每个标题被分割后的词语唯一。
观察 word_count 表中的词语,发现 jieba 默认的词典无法满足需求。
有的词语(如可拆洗、不可拆洗等)却被 cut,这里根据需求对词典加入新词(也可以直接在词典 dict.txt 里面增删,然后载入修改过的 dict.txt)。
词云可视化需要安装 wordcloud 模块。
安装模块有两种方法:
-
pip install wordcloud
-
下载 Packages 安装:pip install 软件包名称
软件包下载地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/#wordcloud
注意:要把下载的软件包放在 Python 安装路径下。在学习Python的过程中,往往因为没有资料或者没人指导从而导致自己不想学下去了,因此姐姐我特意准备了个群 631441315 ,群里有大量的PDF书籍、教程都给大家免费使用!不管是学习到哪个阶段的小伙伴都可以获取到自己相对应的资料!
代码如下:
分析结论:
-
组合、整装商品占比很高。
-
从沙发材质看:布艺沙发占比很高,比皮艺沙发多。
-
从沙发风格看:简约风格最多,北欧风次之,其他风格排名依次是美式、中式、日式、法式等。
-
从户型看:小户型占比最高、大小户型次之,大户型最少。
不同关键词 word 对应的 sales 之和的统计分析
说明:例如词语“简约”,则统计商品标题中含有“简约”一词的商品的销量之和,即求出具有“简约”风格的商品销量之和。
代码如下:
对表 df_word_sum 中的 word 和 w_s_sum 两列数据进行可视化。(本例中取销量排名前 30 的词语进行绘图)
由图表可知:
-
组合商品销量最高。
-
从品类看:布艺沙发销量很高,远超过皮艺沙发。
-
从户型看:小户型沙发销量最高,大小户型次之,大户型销量最少。
-
从风格看:简约风销量最高,北欧风次之,其他依次是中式、美式、日式等。
-
可拆洗、转角类沙发销量可观,也是颇受消费者青睐的。
商品的价格分布情况分析
分析发现,有一些值太大,为了使可视化效果更加直观,这里我们结合自身产品情况,选择价格小于 20000 的商品。
代码如下:
由图表可知:
-
商品数量随着价格总体呈现下降阶梯形势,价格越高,在售的商品越少。
-
低价位商品居多,价格在 500-1500 之间的商品最多,1500-3000 之间的次之,价格 1 万以上的商品较少。
-
价格 1 万元以上的商品,在售商品数量差异不大。
商品的销量分布情况分析
同样,为了使可视化效果更加直观,这里我们选择销量大于 100 的商品。
代码如下:
由图表及数据可知:
-
销量 100 以上的商品仅占 3.4% ,其中销量 100-200 之间的商品最多,200-300 之间的次之。
-
销量 100-500 之间,商品的数量随着销量呈现下降趋势,且趋势陡峭,低销量商品居多。
-
销量 500 以上的商品很少。
不同价格区间的商品的平均销量分布
代码如下:
由图表可知:
-
价格在 1331-1680 之间的商品平均销量最高,951-1331 之间的次之,9684 元以上的最低。
-
总体呈现先增后减的趋势,但最高峰处于相对低价位阶段。
-
说明广大消费者对购买沙发的需求更多处于低价位阶段,在 1680 元以上价位越高,平均销量基本是越少。
商品价格对销量的影响分析
同上,为了使可视化效果更加直观,这里我们结合自身产品情况,选择价格小于 20000 的商品。
代码如下:
由图表可知:
-
总体趋势:随着商品价格增多,其销量减少,商品价格对其销量影响很大。
-
价格 500-2500 之间的少数商品销量冲的很高,价格 2500-5000 之间的商品多数销量偏低,少数相对较高,但价格 5000 以上的商品销量均很低,没有销量突出的商品。
商品价格对销售额的影响分析
代码如下:
由图表可知:
-
总体趋势:由线性回归拟合线可以看出,商品销售额随着价格增长呈现上升趋势。
-
多数商品的价格偏低,销售额也偏低。
-
价格在 0-20000 的商品只有少数销售额较高,价格 2-6 万的商品只有 3 个销售额较高,价格 6-10 万的商品有 1 个销售额很高,而且是最大值。
不同省份的商品数量分布
代码如下:
由图表可知:
- 广东的最多,上海次之,江苏第三,尤其是广东的数量远超过江苏、浙江、上海等地,说明在沙发这个子类目,广东的店铺占主导地位。
- 江浙沪等地的数量差异不大,基本相当。
不同省份的商品平均销量分布
代码如下:
热力型地图
以上是关于淘宝商品数据爬取并分析数据的主要内容,如果未能解决你的问题,请参考以下文章
Python爬虫实战,Scrapy实战,爬取并简单分析知网中国专利数据