前言

前一段时间,创造101很火,这个火是可以理解的,毕竟中国首部女团节目。但是还有一个人不知道为啥突然也火了,那就是我们的菊姐。关于菊姐为什么火,网上已经有很多发文了,这里就不再赘述了。

我们抓取了菊姐的最新微博评论,将评论分词以后制作成如下词云图。

菊粉留言 菊粉全国分布 菊粉分布Top10省份

这里的海外指大陆+港澳台以外的其他所有地方。

除海外用户以外就北上广的用户最多了,这些地方的互联网用户基数本来就大。

菊粉分布Top20城市

因为北京上海比较特殊,北京上海的一些区相当于北京上海这两个省下面的市区,所以你会看到一些北京上海的区域也进入了榜单,比如说朝阳群众。

菊粉星座分布

但是大家都很爱学习,都想要代码学习学习,所以今天就专门来一篇讲讲代码。

在开始具体的代码讲解之前,我需要说明一下关于菊粉人数中摩羯座人数最多这个结论的一些争议,有人评论说微博用户如果不设置年龄的话,默认就是1月1,也就是摩羯座,所以摩羯座人数比较多。先来看两张图:

未设置年龄前的信息 设置个人信息 设置年龄后的信息

通过上面几张截图来看的话,如果未设置年龄时,并不会默认显示成摩羯座,所以应该就不存在大家说的那种情况。

还有所在地和家乡是可以选择则其他的,性别、年龄、星座是不可以选择其他。我们本次就是要获取这几个字段。

本篇主要分为三个部分:

  • 数据获取

  • 数据预处理

  • 可视化图表制作

数据抓取

先讲讲数据抓取的逻辑,最终目的就是要找到pick王菊的人都是哪些人,刚开始想的是直接抓取王菊的粉丝列表,但是后来发现微博数据有限制,只能抓取少量的粉丝列表,所以这个方案行不通,只能换下一个。

在小歪大佬的建议下,决定抓取王菊微博留言下面的用户,因为这些用户是和王菊有过互动的,要比那些只关注没有互动(这里的互动只指评论这一动作)的用户粉的程度要大,更有代表性。

所以最终的一个数据抓取思路就是:通过获取微博评论下的用户,然后进而获取用户基本信息,具体实现代码如下:

获取每条微博评论url

我们先随便点击一条微博的评论进去,看看我们要的字段都在哪里。

最近一条微博的评论

可以看到,有评论text,以及每一条text对应的user_id,找到了字段位置,我们再来看看这些字段对应url是什么,有什么规律。

微博评论url

通过查看这个urlhttps://m.weibo.cn/api/comments/show?id=4248590911655823&page=1,我们大概可以猜出,id前面的部分https://m.weibo.cn/api/comments/show?应该是所有微博评论都一样的,id值是唯一的,每一个id对应一条微博,而page是表示一条微博的评论存放在多页里面,经过验证确实如此,而且page最大值就是100,100以后就不返回数据了。

所以接下来我们的目标就是获取每条微博对应的唯一id值。回到用户主页,

微博id

可以看到每条微博的发布时间,以及微博id,也就是只需要解析用户主页url就可以得到该用户的每条微博对应的id值。

url = https://m.weibo.cn/api/container/getIndex?uid=1773294041&luicode=10000011&lfid=100103type%3D1%26q%3D%E7%8E%8B%E8%8F%8A&featurecode=20000320&containerid=1076031773294041

获取到每条微博的id值以后,我们就可以获取到每条微博评论的url,具体代码如下:

#导入相关库import requestsimport json

comment_parameter = []#用来存放weibo_id值comment_url = []#用来存放weibo_url

#获取每条微博的id值url = 'https://m.weibo.cn/api/container/getIndex?uid=1773294041&luicode=10000011&lfid=100103type%3D1%26q%3D%E7%8E%8B%E8%8F%8A&\featurecode=20000320&type=uid&value=1773294041&containerid=1076031773294041'

c_r = requests.get(url)for i in range(2,11):    c_parameter = (json.loads(c_r.text)["data"]["cards"][i]["mblog"]["id"])    comment_parameter.append(c_parameter)

#获取每条微博评论urlc_url_base = 'https://m.weibo.cn/api/comments/show?id='for parameter in comment_parameter:    for page in range(1,101):#提前知道每条微博只可抓取前100页评论        c_url = c_url_base + str(parameter) + "&page=" + str(page)        comment_url.append(c_url)

获取每个user_id和comment

上面获取到每条微博评论的url以后,我们就可以直接请求对应的url,然后把user_idtext解析出来即可,实现代码如下:

user_id = []#用来存放user_idcomment = []#用来存放commentfor url in comment_url:    u_c_r = requests.get(url)    try:        for m in range(0,9):#提前知道每个url会包含9条用户信息            one_id = json.loads(u_c_r.text)["data"]["data"][m]["user"]["id"]            user_id.append(one_id)            one_comment = json.loads(u_c_r.text)["data"]["data"][m]["text"]            comment.append(one_comment)    except:        pass

获取containerid

获取到了user_id以后,我们再来看看我们想要获取的字段在哪,如下图,

用户信息界面

知道了我们想要获取的字段在哪以后,再看看这些字段对应的url是什么?

用户信息对应url

看到这个url以后我们又可以猜测,每个用户信息对应的url应该只有value&containerid这两个值是不一样的,其他都是一样的,经验证,缺失如此,且value值就是user_idcontainerid是另外一个唯一值,所以我们接下来的目标是获取每个用户对应的containerid。具体实现代码如下:

containerid = []user_base_url = "https://m.weibo.cn/api/container/getIndex?type=uid&value="for id in set(user_id):#需要对user_id去重    containerid_url = user_base_url + str(id)    try:        con_r = requests.get(containerid_url)        one_containerid = json.loads(con_r.text)["data"]['tabsInfo']['tabs'][0]["containerid"]        containerid.append(one_containerid)    except:        containerid.append(0)

获取用户基本信息

知道了user_id以及containerid,我们就可以唯一确定一个用户的基本信息,具体实现代码如下:

#这里需要设置headers以及cookie模拟登陆feature = []#存放用户基本信息id_lose = []#存放请求失败iduser_agent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"headers = {"User-Agent":user_agent}m = 1for num in zip(user_id,containerid):    url = "https://m.weibo.cn/api/container/getIndex?uid="+str(num[0])+"&luicode=10000011&lfid=100103type%3D1%26q%3D&featurecode=20000320&type=uid&value="+str(num[0])+"&containerid="+str(num[1])    try:        r = requests.get(url,headers = headers,cookies = cookie)        feature.append(json.loads(r.text)["data"]["cards"][1]["card_group"][1]["item_content"].split("  "))        print("成功第{}条".format(m))        m = m + 1        time.sleep(1)#设置睡眠一秒钟,防止被封    except:        id_lose.append(num[0])

#将featrue建立成DataFrame结构便于后续分析user_info = pd.DataFrame(feature,columns = ["性别","年龄","星座","国家城市"])

最后的结果如下表:

用户信息表

可以看到,年龄和星座为空,并不是摩羯座,且当年龄和星座为空时,所在地就会错位到年龄列,接下来就做一些数据预处理。

数据清洗

数据清洗逻辑如下:

  • 对于国家列为空,星座列不空且不包含座字,则认为是国家城市名,则把星座列赋值给国家城市列

  • 对于国家列为空,星座列也为空,年龄列不为空且不包含岁或座字,则把年龄列赋值给国家城市列

  • 对于星座列为空,但是年龄列包含座字,则把年龄列赋值给星座列

  • 对于星座列不包含座的,全部赋值为“未知”

  • 对于年龄列不包含岁的,全部赋值为“999岁”(为便于后续好筛选)

  • 对于国家列为空的,全部赋值为“其他”

具体代码如下:

#数据清洗user_info1 = user_info[(user_info["性别"] == "男") | (user_info["性别"] == "女")]#去除掉性别不为男女的部分user_info1 = user_info1.reindex(range(0,5212))#重置索引

user_index1 = user_info1[(user_info1["国家城市"].isnull() == True)&(user_info1["星座"].isnull() == False)                         &(user_info1["星座"].map(lambda s:str(s).find("座")) == -1)].indexfor index in user_index1:    user_info1.iloc[index,3] = user_info1.iloc[index,2]

user_index2 = user_info1[((user_info1["国家城市"].isnull() == True)&(user_info1["星座"].isnull() == True)                          &(user_info1["年龄"].isnull() == False)&(user_info1["年龄"].map(lambda s:str(s).find("岁")) == -1))].indexfor index in user_index2:    user_info1.iloc[index,3] = user_info1.iloc[index,1]

user_index3 = user_info1[((user_info1["星座"].map(lambda s:str(s).find("座")) == -1)&                          (user_info1["年龄"].map(lambda s:str(s).find("座")) != -1))].indexfor index in user_index3:    user_info1.iloc[index,2] = user_info1.iloc[index,1]

user_index4 = user_info1[(user_info1["星座"].map(lambda s:str(s).find("座")) == -1)].indexfor index in user_index4:    user_info1.iloc[index,2] = "未知"

user_index5 = user_info1[(user_info1["年龄"].map(lambda s:str(s).find("岁")) == -1)].indexfor index in user_index5:    user_info1.iloc[index,1] = "999岁"#便于后续统一处理

user_index6 = user_info1[(user_info1["国家城市"].isnull() == True)].indexfor index in user_index6:    user_info1.iloc[index,3] = "其他"

图表制作

主要讲讲这篇报告中涉及到的图表的制作,上一篇文章中的图表我是用的BDP做的,因为BDP做出来的要比python做出来的美观,而且方便,所以我就用了BDP,这篇主要是讲代码,所以就给大家用python实现一遍。

词云图制作

词云图制作是先把一大段话进行分词,分成若干个词语,然后对词语进行计数,最后挑选出出现次数比较大的那些词,绘制在同一张图上,且出现次数越多,字体显示越大,最终效果图如下:

菊粉留言

当然了,最后结果只是右半部分,左半部分是为了对比后期PS加上去的。具体实现代码如下:

import foolfrom collections import Counterfrom PIL import Image,ImageSequence  from wordcloud import WordCloud,ImageColorGenerator

#因留言结构比较乱,所以先保存到本地做进一步处理#删除掉一些html元素pd.DataFrame(comment).to_csv(r"C:\Users\zhangjunhong\Desktop\comment.csv")

#处理完以后再次载入进来comment_data = pd.read_excel(r"C:\Users\zhangjunhong\Desktop\comment.xlsx")

#将数据转换成字符串text = (",").join(comment_data[0])

#进行分词cut_text = ' '.join(fool.cut(text))

#将分词结果进行计数c = Counter(cut_text)c.most_common(500)#挑选出词频最高的500词

#将结果导出到本地进行再一次清洗,删除无意义的符号词pd.DataFrame(c.most_common(500)).to_excel(r"C:\Users\zhangjunhong\Desktop\fenci.xlsx")

#导入背景图,这里选择菊姐头像image = Image.open('C:/Users/zhangjunhong/Desktop/图片1.png')

#将图片信息转换成数组形式graph = np.array(image) 

#设置词云参数 #参数分别是指定字体、背景颜色、最大的词的大小、使用给定图作为背景形状  wc = WordCloud(font_path = "C:\\Windows\\Fonts\\simkai.ttf", background_color = 'White', max_words = 150, mask = graph)  

fp = pd.read_csv(r"C:\Users\zhangjunhong\Desktop\da200.csv",encoding = "gbk")#读取词频文件  name = list(fp.name)#词  value = fp.time#词的频率   dic = dict(zip(name, value))#词以及词频以字典形式存储  

#根据给定词频生成词云wc.generate_from_frequencies(dic)image_color = ImageColorGenerator(graph)  

plt.imshow(wc)  plt.axis("off")#不显示坐标轴  plt.show()

#保存结果到本地wc.to_file('C:/Users/zhangjunhong/Desktop/wordcloud.jpg')

这里分词没有用jieba分词,而是用了fool,据称是最准确的中文分词包,github地址:https://github.com/rockyzhengwu/FoolNLTK

饼图绘制

饼图就很简单了,代码如下:

绘制男女比例的饼图user_info1["性别"].value_counts(normalize = True).plot.pie(title = "菊粉男女分布",autopct='%.2f')

菊粉男女分布

柱状图绘制

先对年龄进行分区间,然后再进行统计绘制,代码如下

#将把年龄从字符串变成数字user_info1["age_1"] = [int(age[:-1]) for age in user_info1["年龄"]]

#对年龄进行分组bins = (0,10,20,25,30,100,1000)#将年龄进行区间切分cut_bins = pd.cut(user_info1["age_1"],bins = bins,labels = False)ax = cut_bins[cut_bins < 5].value_counts(normalize =True).plot.bar(title = "菊粉年龄分布")#将大于100岁的过滤掉ax.set_xticklabels(["0-10岁","10-20岁","20-25岁","25-30岁","30+"],rotation = 0)

菊粉年龄分布

地图绘制

#导入相关库import matplotlib.pyplot as pltimport matplotlibfrom matplotlib.patches import Polygonfrom mpl_toolkits.basemap import Basemapfrom matplotlib.collections import PatchCollection

#将省份和城市进行分列country_data = pd.DataFrame([country.split(" ") for country in user_info1["国家城市"]],columns = ["省份","城市"])

#将国家和城市与user表合并user_data = pd.merge(user_info1,country_data,left_index = True,right_index = True,how = "left")

#按省份进行分组计数shengfen_data = user_data.groupby("省份")["性别"].count().reset_index().rename(columns = {"性别":"人次"})

#需要先对各省份地址进行经纬度解析#导入解析好的省份经纬度信息location = pd.read_table(r"C:\Users\zhangjunhong\Desktop\latlon_106318.txt",sep = ",")

#将省份数据和经纬度进行匹配location_data = pd.merge(shengfen_data,location[["关键词","地址","谷歌地图纬度","谷歌地图经度"]],                    left_on = "省份",right_on = "关键词",how = "left")

#进行地图可视化#创建坐标轴fig = plt.figure(figsize=(16,12))ax  = fig.add_subplot(111)

#需要提前下载中国省份地图的.shp#指明.shp所在路径进行导入basemap = Basemap(llcrnrlon= 75,llcrnrlat=0,urcrnrlon=150,urcrnrlat=55,projection='poly',lon_0 = 116.65,lat_0 = 40.02,ax = ax)basemap.readshapefile(shapefile = "C:/Users/zhangjunhong/Desktop/CHN_adm/CHN_adm1",name = "china")

#定义绘图函数def create_great_points(data):    lon   = np.array(data["谷歌地图经度"])    lat   = np.array(data["谷歌地图纬度"])    pop   = np.array(data["人次"],dtype=float)    name = np.array(data["地址"])    x,y = basemap(lon,lat)    for lon,lat,pop,name in zip(x,y,pop,name):        basemap.scatter(lon,lat,c = "#778899",marker = "o",s = pop*10)        plt.text(lon,lat,name,fontsize=10,color = "#DC143C")

#在location_data上调用绘图函数create_great_points(location_data)

plt.axis("off")#关闭坐标轴plt.savefig("C:/Users/zhangjunhong/Desktop/itwechat.png")#保存图表到本地plt.show()#显示图表

菊粉全国分布

上面地图绘制主要是用的Python中的Basemap库,解析地理位置用的XGeocoding_v2

Top省份和Top城市就是两个柱状图,制作方式和上面的年龄分布类似。

树地图绘制

星座显示的这种可视化形式叫做树地图,主要用的squarify库,实现如下:

import squarify# 创建数据xingzuo = user_info1["星座"].value_counts(normalize = True).indexsize = user_info1["星座"].value_counts(normalize = True).valuesrate = np.array(["34%","6.93%","5.85%","5.70%","5.62%","5.31%","5.30%","5.24%","5.01%","4.78%","4.68%","4.36%"])

# 绘图colors = ['steelblue','#9999ff','red','indianred',          'green','yellow','orange']plot = squarify.plot(sizes = size, # 指定绘图数据                     label = xingzuo, # 指定标签                     color = colors, # 指定自定义颜色                     alpha = 0.6, # 指定透明度                     value = rate, # 添加数值标签                     edgecolor = 'white', # 设置边界框为白色                     linewidth =3 # 设置边框宽度为3                    )# 设置标签大小plt.rc('font', size=10)# 设置标题大小plt.title('菊粉星座分布',fontdict = {'fontsize':12})

# 去除坐标轴plt.axis('off')# 去除上边框和右边框刻度plt.tick_params(top = 'off', right = 'off')

菊粉星座分布

自定义词云图

上面从各个字段介绍了菊粉的特质,最后该来个总结了,总结的形式很多,还是选择词云图的形式,只不过这里不需要进行分词,直接手动输入你要显示的词,以及词的权重(频次)即可,具体代码如下:

image = Image.open('C:/Users/zhangjunhong/Desktop/图片1.png')#作为背景形状的图  graph = np.array(image)  #参数分别是指定字体、背景颜色、最大的词的大小、使用给定图作为背景形状  wc = WordCloud(font_path = "C:\\Windows\\Fonts\\simkai.ttf", background_color = 'White', max_words = 150, mask = graph)  

name = ["女性","摩羯座","20岁","21岁","22岁","23岁","24岁","25岁","广州","杭州","成都","武汉","长沙","上海","北京","海外","美国","深圳"]value = [20,20,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10]#词的频率dic = dict(zip(name, value))#词频以字典形式存储  wc.generate_from_frequencies(dic)#根据给定词频生成词云image_color = ImageColorGenerator(graph)  plt.imshow(wc)  plt.axis("off")#不显示坐标轴  plt.show()wc.to_file('C:/Users/zhangjunhong/Desktop/wordcloud.jpg')


菊粉画像

Python中文社区作为一个去中心化的全球技术社区,以成为全球20万Python中文开发者的精神部落为愿景,目前覆盖各大主流媒体和协作平台,与阿里、腾讯、百度、微软、亚马逊、开源中国、CSDN等业界知名公司和技术社区建立了广泛的联系,拥有来自十多个国家和地区数万名登记会员,会员来自以公安部、工信部、清华大学、北京大学、北京邮电大学、中国人民银行、中科院、中金、华为、BAT、谷歌、微软等为代表的政府机关、科研单位、金融机构以及海内外知名公司,全平台近20万开发者关注。

▼ 点击下方阅读原文免费成为社区会员

Python抓取分析“创造101 ”菊姐微博相关推荐

  1. python 自动抓取分析房价数据——安居客版

    引言 中秋回家,顺便想将家里闲置的房子卖出去.第一次卖房,没经验,于是决定委托给中介.中介要我定个价.最近几年,房价是涨了不少,但是长期在外,也不了解行情.真要定个价,心里还没个数.网上零零散散看了下 ...

  2. 微信好友大揭秘,使用Python抓取朋友圈数据,通过人脸识别全面分析好友,一起看透你的“朋友圈”...

    微信:一个提供即时通讯服务的应用程序,更是一种生活方式,超过数十亿的使用者,越来越多的人选择使用它来沟通交流. 不知从何时起,我们的生活离不开微信,每天睁开眼的第一件事就是打开微信,关注着朋友圈里好友 ...

  3. pythonallowpos_利用Python抓取并分析京东商品评论数据

    2.1 内容简介 本章主要介绍如何利用Python抓取京东商城商品评论信息,并对这些评论信息进行分析和可视化.下面是要抓取的商品信息,一款女士文胸.这个商品共有红色,黑色和肤色等颜色, 70B到90D ...

  4. 使用python抓取并分析数据—链家网(requests+BeautifulSoup)(转)

    本篇文章是使用python抓取数据的第一篇,使用requests+BeautifulSoup的方法对页面进行抓取和数据提取.通过使用requests库对链家网二手房列表页进行抓取,通过Beautifu ...

  5. python新闻评论分析_使用 python 抓取并分析京东商品评论数据

    本篇文章是python爬虫系列的第三篇,介绍如何抓取京东商城商品评论信息,并对这些评论信息进行分析和可视化.下面是要抓取的商品信息,一款女士文胸.这个商品共有红色,黑色和肤色三种颜色, 70B到90D ...

  6. 真小白|一步步教你用Python抓取微信好友分析

    前言 前段时间公司里有个同事发了张图片在群上,是他所有微信好友头像拼成的一张大图,我看着挺有意思,就想自己也搞一下,然后百度了下怎么抓取微信好友之类的--一搜全是用Python抓取的,之前就听说过Py ...

  7. 分析网易云歌曲评论分析加密的JS并且解密,并使用Python抓取歌曲评论

    转载自分析网易云歌曲评论分析加密的JS并且解密,并使用Python抓取歌曲评论 - 『编程语言区』 - 吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn 原文无法显 ...

  8. python数据分析实例:python抓取课工厂网站数据和分析

    在线教育网站学习,是很多人利于闲余时间进行充电的一种选择.本篇文章利用python抓取在线教育网站课工场课程页面的数据,进行简要分析. 通过使用requests库对课工场课程列表页进行抓取. 通过Be ...

  9. 使用Python抓取猫眼近10万条评论并分析

    <一出好戏>讲述人性,使用Python抓取猫眼近10万条评论并分析,一起揭秘"这出好戏"到底如何? 黄渤首次导演的电影<一出好戏>自8月10日在全国上映,至 ...

最新文章

  1. 习题1.8 二分查找 (20 分)
  2. pdo mysql分页_php运用PDO连接数据库,实现分页效果
  3. 数据的中心化和标准化
  4. Java关键字—instanceof
  5. 吴恩达深度学习 —— 4.2 深层网络中的前向传播
  6. Facebook Graph API(2)--读取数据之picture
  7. amap vueamap 与_vue中使用vue-amap(高德地图)
  8. 阿里巴巴开源语音识别声学建模技术
  9. [UI] 精美UI界面欣赏[11]
  10. linux opencv调用笔记本摄像头,Linux下利用Opencv打开笔记本摄像头问题
  11. 《Rework》摘录及感想
  12. 麦氏细菌浊度分析仪的校准物质选择
  13. html怎么给图片加倒影,用CSS3实现图片倒影效果,同时给出兼容早期版本IE的方案...
  14. spark.jars.packages使用镜像源加速
  15. 室友在宿舍玩游戏我学java_在宿舍写代码总被一个室友认为在装逼,该怎么办?...
  16. class ts 扩展方法_ts各种类型和用法
  17. 【数据结构】单链表(增、删、查、改)的实现 [初阶篇_ 复习专用]
  18. 虚拟机 Ubuntu16.04开机蓝屏问题
  19. OpenCloner Ripper:集光盘翻录软件+光盘视频转换+光盘解密于一体的全能光盘工具
  20. AZ-204认证考试攻略

热门文章

  1. 数据中心基础设施管理(DCIM)的市场价值
  2. DataX之MySQL-overwrite-HIVE
  3. 22、关于破解滑动的验证码
  4. 计算机主板pci插槽,PCI插槽:濒临淘汰依然有用
  5. 模拟售票大厅实例——多线程时访问共享变量时的安全(CMutex或CCriticalSection的应用)
  6. CFileDialog使用
  7. 最美人间四月天,送3本Python好书
  8. 计算机网络第七版谢希仁知识点总结
  9. Processing 3 中手动添加系统库(processing.* )
  10. 装饰者模式(带例子)