前言
- 蛋肥通过Python爬虫获取豆瓣电影TOP250数据的练习,掌握了爬虫的基本知识,然后蛋肥又去拜读了很多高手的爬虫实例,发现自己在最后的数据分析上实在乏善可陈,所以这一次尝试将更多的时间用在数据分析上,看能否得出一些有趣的信息。
准备
爬取时间:2020/11/26
系统环境:Windows 10
所用工具:Jupyter Notebook\Python 3.0
涉及的库:requests\lxml\pandas\matplotlib\datetime\jieba\stylecloud
获取基础数据
蛋肥想法:为了获取更多的信息,蛋肥打算先将产品运营分类下所有文章的网址爬取下来,然后再进入文章页面,爬取题目、作者、评论等详细信息。
产品运营|人人都是产品经理
http://www.woshipm.com/category/operate
参考资料
用python的xpath和requests库爬取图片超详细实例
如何在python中把两个列表的各项分别合并为列表
Max retries exceeded with url问题解决
requests关于Exceeded 30 redirects问题得出的结论
爬取产品运营分类下所有文章的网址
import requests
from lxml import etree
#爬取产品运营分类下所有文章的网址
def gethref():
href=[]
#伪造请求头
headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0"}
#循环解决翻页问题
for i in range(1,863):
link="http://www.woshipm.com/category/operate/page/"+str(i)
r=requests.get(link,headers=headers,timeout=10)
print(str(i),r.status_code)
#爬取对应xpath下的数据并存入列表
html=etree.HTML(r.text)
href_t=html.xpath('//h2[@class="post-title"]/a/@href')
href.extend(href_t)
return(href)
#执行函数
href=gethref()
爬取文章详细信息
#爬取文章详细信息
def getinfo(list):
info=[]
#伪造请求头
headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0"}
#遍历每个链接
for i in range(len(list)):
link=list[i]
#增加重试连接次数
requests.DEFAULT_RETRIES=5
#关闭多余连接
s=requests.session()
s.keep_alive=False
r=requests.get(link,headers=headers,timeout=300,allow_redirects=False)
print(str(i),r.status_code)
#依次爬取题目、作者、发布时间、评论数、浏览量、收藏数、预计阅读时间、作者头像
html=etree.HTML(r.text)
title=html.xpath('//h2[@class="article--title"]/text()')
author=html.xpath('//div[@class="author u-flex"]/a/text()')
time=html.xpath('//div[@class="meta--sup"]/time/text()')
comment=html.xpath('//div[@class="meta--sup__right"]/text()[1]')
read=html.xpath('//div[@class="meta--sup__right"]/text()[2]')
collect=html.xpath('//div[@class="meta--sup__right"]/text()[3]')
lenth=html.xpath('//div[@class="meta--sup__right"]/el-tooltip/span/text()')
pic=html.xpath('//div[@class="u-flex0"]/a/img/@src')
info_t=[[a,b,c,d,e,f,g,h] for a,b,c,d,e,f,g,h in zip(title,author,time,comment,read,collect,lenth,pic)]
info.extend(info_t)
return(info)
#执行函数,如果执行时老是崩,可以分段执行最后拼接(蛋肥就是这样做的,只是为了代码好看没写出来)
data=getinfo(href)
数据预处理
蛋肥想法:经观察数据整体问题不大,检查缺失、去除空格、转化数据格式,最后将数据保存为xlsx。
小插曲
len(href)为10335,len(data)为10334,找了半天,才发现有一个文章禁止访问了,不知道因为啥原因,于是蛋肥便抛弃了它。
from datetime import datetime
#去除空格及不需要的字符,调整格式
for i in range(len(data)):
data[i]=[x.replace("\n","").replace(" ","") for x in data[i]]
data[i][2]=datetime.strptime(data[i][2],'%Y-%m-%d')
data[i][3]=int(data[i][3].replace("评论",""))
data[i][5]=int(data[i][5].replace("收藏",""))
data[i][6]=int(data[i][6].replace("分钟",""))
#因浏览量存在过万的情况,如"1.2万",做一下转换
if("万"in data[i][4]):
data[i][4]=int(float(data[i][4].replace("浏览","").replace("万",""))*10000)
else:
data[i][4]=int(data[i][4].replace("浏览",""))
import pandas as pd
#保存数据
df=pd.DataFrame(data,columns=["题目","作者","日期","评论数","浏览数","收藏数","时长","作者头像"])
df.info()
df.to_excel(r"C:\Users\Archer\Desktop\爬取数据.xlsx",index=False)
数据可视化
蛋肥想法:数据相关图贴到数据分析中,此处只记录绘图代码,如想直接看分析,建议疯狂下滑。
import matplotlib.pyplot as plt
#画图四件套:显示、矢量、中文、负号
%matplotlib inline
%config InlineBackend.figure_format="svg"
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
绘制季度发文量变化趋势
参考资料
Python将数据框中的每日数据汇总到每月和每季度
python绘图保存的图像坐标轴显示不全以及图片周围空白较大的问题
#绘制季度发文量变化趋势
#为了不影响原数据表,重新建一个来操作数据
df_num=df.copy()
df_num.set_index("日期",inplace=True)
x=list(df_num.resample('QS').count().index)
y=list(df_num.resample('QS').count()["题目"])
#开始绘图
plt.figure(figsize=(12,5))
plt.subplot(1,1,1)
plt.plot(x,y)
#设置数据标签
for a,b in zip(x,y):
plt.text(a,b,b,ha="center",va="bottom",fontsize=10)
#设置其他
plt.title("季度发文量变化趋势",fontsize=15)
plt.xticks(x,rotation=90)
#保存图片
plt.savefig(r"C:\Users\Archer\Desktop\季度发文量变化趋势.png",bbox_inches="tight")
绘制作者(发文总量>90)发文量变化趋势
小提示
所有作者发文量变化趋势,在下面的代码中去除筛选条件并做些许修改即可,故不另贴代码
参考资料
python如何水平显示图例元素
#筛选发文总量>90的作者
df_90=df.groupby("作者").count().sort_values("题目",ascending=False)
df_90=df_90[df_90["题目"]>90]
#将作者数据存入列表
author=list(df_90.index)
#开始绘图,因为老曹前期发布了大量文章,为了不影响其他数据显示,设置y轴范围(0,120)
plt.figure(figsize=(12,5))
plt.subplot(1,1,1)
plt.title("发文总量>90的作者发文量变化趋势",fontsize=15)
plt.ylim(0,120)
#循环绘制每一个作者的趋势曲线
for i in range(len(author)):
df_author=df[df["作者"]==author[i]].copy()
df_author.set_index("日期",inplace=True)
x=list(df_author.resample('QS').count().index)
y=list(df_author.resample('QS').count()["题目"])
plt.plot(x,y,label=author[i])
#与【季度发文量变化趋势】统一横坐标轴
date=list(df_num.resample('QS').count().index)
plt.xticks(date,rotation=90)
#添加横向图例
plt.legend(loc="upper left",ncol=8)
#保存图片
plt.savefig(r"C:\Users\Archer\Desktop\作者发文量变化趋势.png",bbox_inches="tight")
绘制发文量排行榜
#绘制发文量排行榜
from datetime import datetime
#为了不影响原数据表,重新建一个来操作数据
df_r=df.copy()
df_r.set_index("日期",inplace=True)
#绘制画布
plt.figure(figsize=(14,18))
#遍历每一年的排行榜
for i in range(0,9):
df_m=df_r[(df_r.indexdatetime(2012+i,1,1))].groupby("作者").count().sort_values("题目")[-5:]
x=list(df_m.index)
y=list(df_m["题目"])
plt.subplot(5,2,i+1)
plt.barh(x,y)
plt.title(str(2012+i)+"年发文量TOP5",fontsize=15)
#添加数据标签
for a,b in zip(x,y):
plt.text(b,a,b,ha="left",va="center",fontsize=10)
#隐藏xticks,节约空间
plt.xticks([])
#保存图片
plt.savefig(r"C:\Users\Archer\Desktop\发文量排行榜.png",bbox_inches="tight")
文章互动总数TOP10系列
#文章-浏览总数TOP10
df_read=df.sort_values("浏览数",ascending=False)[0:10].iloc[:,[0,1,2,4]]
#文章-评论总数TOP10
df_comment=df.sort_values("评论数",ascending=False)[0:10].iloc[:,[0,1,2,3]]
#文章-收藏总数TOP10
df_collect=df.sort_values("收藏数",ascending=False)[0:10].iloc[:,[0,1,2,5]]
作者互动总数TOP10系列
#作者-浏览总数TOP10
df_a_read=df.groupby("作者").aggregate({"浏览数":"sum"}).sort_values("浏览数")[-10:]
#作者-评论总数TOP10
df_a_comment=df.groupby("作者").aggregate({"评论数":"sum"}).sort_values("评论数")[-10:]
#作者-收藏总数TOP10
df_a_collect=df.groupby("作者").aggregate({"收藏数":"sum"}).sort_values("收藏数")[-10:]
#绘制画布
plt.figure(figsize=(12,15))
#绘制作者-浏览总数TOP10
plt.subplot(3,1,1)
plt.title("作者-浏览总数TOP10",fontsize=15)
x=list(df_a_read.index)
y=list(df_a_read["浏览数"])
plt.barh(x,y)
for a,b in zip(x,y):
plt.text(b,a,b,ha="left",va="center",fontsize=10)
#隐藏xticks,节约空间
plt.xticks([])
#绘制作者-评论总数TOP10
plt.subplot(3,1,2)
plt.title("作者-评论总数TOP10",fontsize=15)
x=list(df_a_comment.index)
y=list(df_a_comment["评论数"])
plt.barh(x,y)
for a,b in zip(x,y):
plt.text(b,a,b,ha="left",va="center",fontsize=10)
#隐藏xticks,节约空间
plt.xticks([])
#绘制作者-收藏总数TOP10
plt.subplot(3,1,3)
plt.title("作者-收藏总数TOP10",fontsize=15)
x=list(df_a_collect.index)
y=list(df_a_collect["收藏数"])
plt.barh(x,y)
for a,b in zip(x,y):
plt.text(b,a,b,ha="left",va="center",fontsize=10)
#隐藏xticks,节约空间
plt.xticks([])
#保存图片
plt.savefig(r"C:\Users\Archer\Desktop\作者互动排行榜.png",bbox_inches="tight")
作者互动平均数TOP10系列
python中关于round函数的小坑
#作者-浏览平均数TOP10
df_a_read_mean=df.groupby("作者").aggregate({"浏览数":"sum","题目":"count"}).sort_values("浏览数")
df_a_read_mean.insert(2,"平均",df_a_read_mean["浏览数"]//df_a_read_mean["题目"])
df_a_read_mean=df_a_read_mean[df_a_read_mean["题目"]>10].sort_values("平均")[-10:]
#作者-评论平均数TOP10
df_a_comment_mean=df.groupby("作者").aggregate({"评论数":"sum","题目":"count"}).sort_values("评论数")
df_a_comment_mean.insert(2,"平均",df_a_comment_mean["评论数"]//df_a_comment_mean["题目"])
df_a_comment_mean=df_a_comment_mean[df_a_comment_mean["题目"]>10].sort_values("平均")[-10:]
#作者-收藏平均数TOP10
df_a_collect_mean=df.groupby("作者").aggregate({"收藏数":"sum","题目":"count"}).sort_values("收藏数")
df_a_collect_mean.insert(2,"平均",df_a_collect_mean["收藏数"]//df_a_collect_mean["题目"])
df_a_collect_mean=df_a_collect_mean[df_a_collect_mean["题目"]>10].sort_values("平均")[-10:]
#绘制画布
plt.figure(figsize=(12,15))
#绘制作者-浏览平均数TOP10
plt.subplot(3,1,1)
plt.title("作者-浏览平均数TOP10",fontsize=15)
x=list(df_a_read_mean.index)
y=list(df_a_read_mean["平均"])
plt.barh(x,y)
for a,b in zip(x,y):
plt.text(b,a,b,ha="left",va="center",fontsize=10)
#隐藏xticks,节约空间
plt.xticks([])
#绘制作者-评论平均数TOP10
plt.subplot(3,1,2)
plt.title("作者-评论平均数TOP10",fontsize=15)
x=list(df_a_comment_mean.index)
y=list(df_a_comment_mean["平均"])
plt.barh(x,y)
for a,b in zip(x,y):
plt.text(b,a,b,ha="left",va="center",fontsize=10)
#隐藏xticks,节约空间
plt.xticks([])
#绘制作者-收藏平均数TOP10
plt.subplot(3,1,3)
plt.title("作者-收藏平均数TOP10",fontsize=15)
x=list(df_a_collect_mean.index)
y=list(df_a_collect_mean["平均"])
plt.barh(x,y)
for a,b in zip(x,y):
plt.text(b,a,b,ha="left",va="center",fontsize=10)
#隐藏xticks,节约空间
plt.xticks([])
#保存图片
plt.savefig(r"C:\Users\Archer\Desktop\作者互动平均排行榜.png",bbox_inches="tight")
绘制标题热词词云(以2020年为例)
参考资料
一款高颜值的词云包让我拍案叫绝
Python分词云图:中英文Stylecloud调用代码精校,可拿来直接用
Tableau Palettes
import jieba
from stylecloud import gen_stylecloud
#筛选2020年的标题,简单去掉中文停用词,建议去网上下更全的词表
df_c=df[(df["日期"]datetime(2020,1,1))]
textc=list(df_c["题目"])
textstop=["的","如何","是","与","和","你","从","怎么","到","做","什么","了","个","在","好"]
for i in range(len(textc)):
for j in range(len(textstop)):
textc[i]=textc[i].replace(textstop[j],"")
#保存成txt
file=open(r"C:\Users\Archer\Desktop\2020题目.txt","a+",encoding='utf-8')
for i in range(len(textc)):
s=str(textc[i])
file.write(s)
file.close()
#直接复制词云代码,icon_name对应词云轮廓,palette对应配色
def jieba_cloud(file_name):
with open(file_name,'r',encoding='utf8') as f:
word_list = jieba.cut(f.read())
result = " ".join(word_list)
#制作中文云词
gen_stylecloud(text=result,palette='tableau.BlueRed_6',icon_name='fas fa-comment',font_path='C:\\Windows\\Fonts\\simhei.ttf',output_name=file_name.split('.')[0] + '.png')
if __name__ == "__main__":
file_name = r"C:\Users\Archer\Desktop\2020题目.txt"
jieba_cloud(file_name)
题目长度相关性
df_title=df.copy()
#新增列记录题目长度
df_title["题目长度"]=df_title['题目'].str.len()
df_title_c=df_title.groupby("题目长度").count()
#绘制画布
plt.figure(figsize=(12,20))
#绘制题目长度分布
plt.subplot(4,1,1)
#设置横纵坐标轴
plt.xlabel("题目长度")
plt.ylabel("数量")
#设置标题
plt.title("题目长度 分布")
#绘制分布图
plt.bar(df_title_c.index,df_title_c["题目"])
#绘制题目长度-浏览数相关性
plt.subplot(4,1,2)
#设置横纵坐标轴
plt.xlabel("题目长度")
plt.ylabel("浏览数")
#设置标题
plt.title("题目长度-浏览数 相关性")
#绘制散点图
plt.scatter(df_title["题目长度"],df_title["浏览数"])
#绘制题目长度-评论数相关性
plt.subplot(4,1,3)
#设置横纵坐标轴
plt.xlabel("题目长度")
plt.ylabel("评论数")
#设置标题
plt.title("题目长度-评论数 相关性")
#绘制散点图
plt.scatter(df_title["题目长度"],df_title["评论数"])
#绘制题目长度-收藏数相关性
plt.subplot(4,1,4)
#设置横纵坐标轴
plt.xlabel("题目长度")
plt.ylabel("收藏数")
#设置标题
plt.title("题目长度-收藏数 相关性")
#绘制散点图
plt.scatter(df_title["题目长度"],df_title["收藏数"])
#保存图片
plt.savefig(r"C:\Users\Archer\Desktop\题目长度相关性.png",bbox_inches="tight")
文章时长相关性
df_time=df.copy()
df_time_c=df_time.groupby("时长").count()
#绘制画布
plt.figure(figsize=(12,20))
#绘制文章时长分布
plt.subplot(4,1,1)
#设置横纵坐标轴
plt.xlabel("文章时长")
plt.ylabel("数量")
#设置标题
plt.title("文章时长 分布")
#绘制分布图
plt.bar(df_time_c.index,df_time_c["题目"])
#绘制文章时长-浏览数相关性
plt.subplot(4,1,2)
#设置横纵坐标轴
plt.xlabel("文章时长")
plt.ylabel("浏览数")
#设置标题
plt.title("文章时长-浏览数 相关性")
#绘制散点图
plt.scatter(df_time["时长"],df_time["浏览数"])
#绘制文章时长-评论数相关性
plt.subplot(4,1,3)
#设置横纵坐标轴
plt.xlabel("文章时长")
plt.ylabel("评论数")
#设置标题
plt.title("文章时长-评论数 相关性")
#绘制散点图
plt.scatter(df_time["时长"],df_time["评论数"])
#绘制文章时长-收藏数相关性
plt.subplot(4,1,4)
#设置横纵坐标轴
plt.xlabel("文章时长")
plt.ylabel("收藏数")
#设置标题
plt.title("文章时长-收藏数 相关性")
#绘制散点图
plt.scatter(df_time["时长"],df_time["收藏数"])
#保存图片
plt.savefig(r"C:\Users\Archer\Desktop\文章时长相关性.png",bbox_inches="tight")
数据分析
发文
发文量趋势
- 季度发文量变化趋势,可以看出存在四次明显的下降节点,“2012-04-01~2012-07-01”是因为人人都是产品经理CEO老曹大幅减少了发文数量;“2020-07-01~2020-10-01”是因为第四季度不完整;“2013-07-01~2014-04-01”和“2017-10-01~2018-04-01”下降的原因未知。
- 鉴于第一个下降节点是因为主创老曹减少了发文,蛋肥猜想后两次下降是否因为同样的原因,于是蛋肥筛选出了发文总量>90的作者,追踪其发文趋势,得到发文总量>90的作者发文量变化趋势,可以看出下降节点基本上是吻合的,同时观察所有作者发文量变化趋势,也基本吻合。
- 推测,人人都是产品经理|产品运营版块,“2012-04-01~2013-07-01”主要是主创人员(或种子用户)发文进行版块的启动,该阶段用户还处于观望的态势;“2013-07-01~2014-04-01”主创人员(或种子用户)减少了发文,发文总量陡降,说明自然用户还未参与到版块的循环来;“2014-04-01~2017-10-01”主创人员(或种子用户)的发文量波动下降中,但整体发文量却呈现上升的趋势,追踪将所有作者的发文趋势,可以看到这段时间内发文量在0-10这个区间的作者开始增多,同时存在不少10-15这个区间的作者,说明自然用户逐渐参与到版块内容的构建中,热度引发了热情,不少专业自媒体也参与其中;“2017-10-01~2020-10-01”这段时间热情逐渐消散,版块回归理性,发文总量陡降后开始缓慢回升,且2020年由于疫情原因出现小波峰。
发文量排行榜
-
江山代有才人出,各领风骚每一年哇,看得出“老虎讲运营”、“野生的独孤菌”近三年开始发力,可以关注一下,只是不知曾经叱诧风云的“魏家东”、“米可”现在又身在何方~
互动
- 整体来看,用户评论数、收藏数偏低,看来大多数都是“朕已阅”的心态;作者互动平均数据,蛋肥挑选了发文量大于10的作者统计(避免单篇文章平均数据偏大),这些数据可作为一个标尺,如果你发文量大于10且三项数据能达到这个水准,那么恭喜你,你已经是人人都是产品经理的顶部KOL了。
- 蛋肥认为可以从浏览、评论、收藏三个方面对文章(或作者)进行一个加权打分,然后就可以排出一个最具有含金量的TOP榜单,但是这个加权系数怎么设置蛋肥没有经验,所以这次先略过(还是因为懒)。
文章-浏览总数TOP10
文章-评论总数TOP10
文章-收藏总数TOP10
作者-互动总数排行榜
作者-互动平均数排行榜
标题热词
- 单纯从标题词云中可以看出,2012-2014年“营销”是主旋律,更多的看重如何将产品卖出去、如何提高产品的知名度,市场以抢占用户为主;从2015年开始,“运营”取而代之,很多产品的用户量接近或已经触及天花板,如何利用产品运营的技巧,尽可能大地利用这部分用户的价值成为关注的重点;2019年开始,“增长”逐步成为热议话题,无论是私域流量、社区流量,还是细分长尾市场、跨界合作等,目标都是寻求突破用户天花板,获得更多的增长空间。
相关性
题目长度与浏览数、评论数、收藏数的关系
文章时长与浏览数、评论数、收藏数的关系
总结
- 数据分析,最好提前设立目标,不然在选取数据、数据可视化时没有方向性,不能为了分析而分析(当然练习除外)。
- 数据中确实隐含着很多信息,随着数据维度、时间维度、数据量等的增加,数据中所能蕴含的信息或规律也会增多,可以揭示更深层次的数据关联,这应该就是大数据的概念。