正文
来自:51CTO技术栈(微信号:blog51cto)
最近一段时间,《创造101》很火,这个火是可以理解的,毕竟这是中国首部女团节目。但是还有一个人不知道为啥突然也火了,那就是我们的菊姐。
关于菊姐为什么会火,网上有很多文章,我就不再赘述了。今天我们就来做一份菊粉陶渊明的用户画像,看看那些 Pick 菊姐的人都有什么特质?
先来看看百度指数,通过百度指数我们看出,菊姐的搜索热度在 5 月 30 开始出现顶峰,5 月 31 开始回落。
王菊百度指数
再来看看微信指数,与百度指数趋势基本一致,但起伏感要稍强于百度指数。
王菊微信指数
我们再来看看菊姐的需求图谱,即与菊姐相关的话题都有哪些。
王菊需求图谱
相关词主要有:创造101,王菊,王菊旧照,王菊年龄,看来大家很关心菊姐的个人信息哈,尤其是旧照。
王菊新旧照
看看菊姐以前的照片,再看看现在的,我只想问一句,菊姐这些年都经历了什么?
了解了这些以后,我们切换到今天的主题,菊粉到底都是哪些人?于是我用 Python 爬了菊姐的两万条微博评论,并做了分析!
爬取数据来源于王菊最新微博评论数据,本次数据采集的思路主要是:
-
先获取王菊最新几条(关于创造101话题)的微博评论 url
-
然后依次去遍历每条 url 下面的留言以及 user_id
-
在拿到 user_id 以后再去依次遍历每个用户的基本信息
具体实现代码如下:
#导入所需库import jsonimport timeimport numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport matplotlibimport squarifyfrom matplotlib.patches import Polygonfrom mpl_toolkits.basemap import Basemapfrom matplotlib.collections import PatchCollection#获取每条微博评论的url参数def get_comment_parameter(): 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) return comment_parameterif __name__ == "__main__": comment_parameter = []#用来存放微博url参数 comment_url = []#用来存放微博url user_id = []#用来存放user_id comment = []#用来存放评论 containerid = []#用来存放containerid feature = []#用来存放用户信息 id_lose = []#用来存放访问不成功的user_id get_comment_parameter() #获取每条微博评论url c_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) #获取每个url下的user_id以及评论 for 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 #获取每个user对应的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对应的基本信息 #这里需要设置cookie和headers模拟请求 user_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 = 1 for 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] = "其他"
我们抓取了菊姐的最新微博评论,将评论分词以后制作成如下词云图,代码如下:
import foolfrom collections import Counterfrom PIL import Image,ImageSequence from wordcloud import WordCloud,ImageColorGenerator#因留言结构比较乱,所以先保存到本地做进一步处理pd.DataFrame(comment).to_csv(r"C:UserszhangjunhongDesktopcomment.csv")#处理完以后再次载入进来comment_data = pd.read_excel(r"C:UserszhangjunhongDesktopcomment.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:UserszhangjunhongDesktopenci.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:UserszhangjunhongDesktopda200.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
排名前三的热词分别是:“加油”、“哈哈”、“菊姐”,可以看出大家对菊姐的态度大多还是支持的态度。
绘制男女比例的饼图ax = user_info1["性别"].value_counts(normalize = True).plot.pie(title = "菊粉男女分布",autopct='%.2f')