七夕将至,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 库请求网页内容,需要注意的是,在请求页面信息时,需要构造请求头中的 cookie 和 user-agent 信息,否则并不会得到有效响应,获取 cookie 和 user-agent 信息需要在浏览器“开发者工具” 中的网络 标签下单击当前请求页面(如果网络 标签下没有当前请求的页面,需要刷新后才可以显示),在标头 选项卡中找到请求标头 的 cookie 和 user-agent 值并复制,按照以下方式构造请求头:
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":"...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])
因此需要使用以下方式进行正确解码:
decodeunichars = detail_url[4].encode('utf-8').decode('unicode-escape')
print(decodeunichars)
🕸? 将数据写入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":"..."
}
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(',', ' ')
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)
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__)
file = open(path.join(d, 'text.txt')).read()
stopwords = ["七夕","七夕情人节","情人节","男友","女友","男生","女生","女朋友","男朋友","礼物","生日礼物","创意","实用","朋友","男士","老婆","老公","直营","闺蜜","结婚","送给"]
text_split = jieba.cut(file)
text_split_no = []
for word in text_split:
if word not in stopwords:
text_split_no.append(word)
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)
??礼物清单??
玩偶/公仔/毛绒玩具/抱抱熊
糖果
项链
巧克力
相册/纪念册
零食/小吃
手链/手镯/镯子
玫瑰
吊坠
小夜灯
音乐盒/八音盒
戒指/对戒
口红
手绳/红绳
耳钉
👧 送女朋友礼物清单
以同样的方法,将关键字改为“女友+礼物” ,可以得到??送女朋友礼物清单??:
小夜灯
相册/纪念册/相框
刻字类礼物
八音盒
项链/手链/手镯/镯子
口红
手表
包
水晶鞋
玩偶
👦 送男朋友礼物清单
最后,将关键字改为“男友+礼物” ,可以得到??送男朋友礼物清单??:
可乐刻字
相册/纪念册/相框
花束
手办
摆件
钥匙扣
木刻画
情书
刺绣
篮球
可以看出,送女朋友和男朋友的礼物还是有一些差别的。 当然,和主管感觉上有很些差异的原因可能在于,很多商品的标题太过创意,完全不包含商品。
下一步计划
下一步的工作包括:
- 获取商品的评价信息,将购买者的评论信息也融合到计算权重中去,根据购买者的评价对商品排序进行修正,例如可能去除一些华而不实的“智商税”产品,同时可能得到一些小众好评的商品。
- 利用深度学习相关技术,识别图片中商品,用以解决一些商品标题及商品图片文字中完全不包含商品名的情况,让我们明白标题为《生日礼物女生七夕情人节给闺蜜送女友朋友送给女孩的实用小高级感》的商品到底卖的是什么?
写在最后
当然,本文仅做分析之用,结果也仅供参考,如果清单里没有令你心仪的礼物,也可以选择红包或者清空购物车的方式。无论送女朋友/男朋友什么礼物,传达自己的??心意??最重要了。
|