中国情人节——七夕节(别称:乞巧节、七巧节、七姐诞、道德腊,英文名:Double Seventh Festival)被赋予了“牛郎织女”的美丽爱情传说,使其成为了象征爱情的节日,从而被认为是中国最具浪漫色彩的传统节日,日期是每一年农历七月初七,有拜月祈福、拜织女、吃巧果、乞求姻缘等习俗。html
随着七夕的临近,不少小伙伴都开始筹备送女友/男友的礼物了,礼物做为一种传达情感的媒介,表达了对于女友/男友的祝福和心意,但同时对于要送什么礼物,对于不少小伙伴来说却是选择困难,本文利用 Python 爬取某宝商品页面,为小伙伴们分析销量较高的礼物清单,以供你们参考。浏览器
根据不一样关键字,爬取“某宝”
获取商品信息(以“七夕礼物”
、“七夕礼物送男朋友”
、“七夕礼物送女朋友”
等为例),根据所获取数据分析获得七夕礼物清单,并经过词云
可视化的方式展现不一样礼物的频率比重对比。markdown
爬虫少不了网址,所以首先观察网址的构成,在输入关键字“七夕礼物”
进行搜索时,发现网址中 q
的参数值即为所键入的关键字“七夕礼物”
,以下图所示:cookie
所以可使用如下方式构造网址:网络
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
变量,例如要爬取关键字“七夕礼物送男朋友”
,只须要作以下修改:app
q_value = "七夕礼物送男朋友"
复制代码
使用浏览器“开发者工具”
,观察网页结构,能够看出商品的信息都是在 <script>
中,工具
所以,首先使用 requests 库请求网页内容,须要注意的是,在请求页面信息时,须要构造请求头中的 cookie 和 user-agent 信息,不然并不会获得有效响应,获取 cookie 和 user-agent 信息须要在浏览器“开发者工具”中的网络标签下单击当前请求页面(若是网络标签下没有当前请求的页面,须要刷新后才能够显示),在标头选项卡中找到请求标头的 cookie 和 user-agent 值并复制,按照如下方式构造请求头:oop
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
值):字体
获得响应网页后,须要使用 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文件存储数据
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)
复制代码
❤️礼物清单❤️
玩偶/公仔/毛绒玩具/抱抱熊
糖果
项链
巧克力
相册/记念册
零食/小吃
手链/手镯/镯子
玫瑰
吊坠
小夜灯
音乐盒/八音盒
戒指/对戒
口红
手绳/红绳
耳钉
复制代码
以一样的方法,将关键字改成“女朋友+礼物”
,能够获得❤️送女友礼物清单❤️:
小夜灯
相册/记念册/相框
刻字类礼物
八音盒
项链/手链/手镯/镯子
口红
手表
包
水晶鞋
玩偶
复制代码
最后,将关键字改成“男朋友+礼物”
,能够获得❤️送男友礼物清单❤️:
可乐刻字
相册/记念册/相框
花束
手办
摆件
钥匙扣
木刻画
情书
刺绣
篮球
复制代码
能够看出,送女友和男友的礼物仍是有一些差异的。 固然,和主观感受上有很些差别的缘由可能在于,不少商品的标题太过创意,彻底不包含商品。
固然,本文仅作分析之用,结果也仅供参考,若是清单里没有令你心仪的礼物,也能够选择红包或者清空购物车的方式。不管送女友/男友什么礼物,传达本身的❤️心意❤️最重要了。
文章的项目代码,往期的文章可免费领取,私信小编:06便可。