南京音乐推荐联合社

【技术顾问分享】基于Python的微信好友分析

西电青苔工作室 2019-05-14 16:34:00

《源来》是一款在互联网技术领域内,帮助大学生用户解决问题、基于地理位置发现用户,致力于在用户之间建立弱社交网络的社区型应用。


技术顾问是由30名互联网领域的技术大咖组成,负责《源来》应用初期的技术解答与后期的技术监督。

 

很荣幸邀请到《源来》的技术顾问,每周一为大家带来一篇新颖的干货分享。


本期为后台方向技术顾问肖洒的分享


基于Python的微信好友分析

“如果我比别人看得远,那是因为我站在巨人的肩膀上”–不知道牛顿说了没❀(๑╯◡╰๑)❀


本文利用Python3的itchat包简单的分析了一下自己的微信好友。


1. itchat

  • itchat是一个开源的微信个人号接口,使用python调用微信从未如此简单。


  • 使用不到三十行的代码,你就可以完成一个能够处理所有信息的微信机器人。


  • 当然,该api的使用远不止一个机器人,更多的功能等着你来发现,比如这些。


  • 该接口与公众号接口itchatmp共享类似的操作方式,学习一次掌握两个工具。


  • 如今微信已经成为了个人社交的很大一部分,希望这个项目能够帮助你扩展你的个人的微信号、方便自己的生活。


2. 运行环境

本文采用Python3,然后顺便吐槽下Python的向后不兼容真的好烦好烦,真的是体验超差。当然为了解决这个不是问题的小问题,我装了两个运行环境,毕竟是要站在巨人肩膀上去瞭望远方,那就站在两个肩膀上好了。sublime的Python3和2的配置,地址如下:


https://x-nicolo.github.io/2017/09/15/Python-Opencv%E7%9A%84%E5%AE%89%E8%A3%85/

 
关于Pycharm里面Py2和Py3的转换更是简单,百度一下就ok。转换如下:



3. 准备

需要安装itchat、matplotlib、numpy等依赖。
老生常谈之安装方式:

  1. pip install itchat

  2. pip install matplotlib

  3. pip install numpy

  4. pip install PIL/Pillow


注意:是不是上面的命令我早都忘了(我此时此刻觉得应该是这样的!),所以。。你们自己看着安装吧,反正不出问题都感觉不正常。按照使用的Python运行环境来安装相应的依赖包。pip/pip3


安装包介绍

itchat

本文的主角,我给它起个slogan吧“不仅仅是微信机器人。”



Matplotlib

Matplotlib是Python的可视化包。


Matplotlib是Python中最常用的可视化工具之一,可以非常方便地创建海量类型地2D图表和一些基本的3D图表。Matplotlib最早是为了可视化癫痫病人的脑皮层电图相关的信号而研发,因为在函数的设计上参考了MATLAB,所以叫做Matplotlib。Matplotlib首次发表于2007年,在开源和社区的推动下,现在在基于Python的各个科学计算领域都得到了广泛应用。Matplotlib的原作者John D. Hunter博士是一名神经生物学家,2012年不幸因癌症去世,感谢他创建了这样一个伟大的库。



numpy

Numpy是Python的科学计算包。


numpy(Numerical Python extensions)是一个第三方的Python包,用于科学计算。这个库的前身是1995年就开始开发的一个用于数组运算的库。经过了长时间的发展,基本上成了绝大部分Python科学计算的基础包,当然也包括所有提供Python接口的深度学习框架。


关于Matplotlib和numpy,推荐知乎上的一篇文章,感觉不错:给深度学习入门者的Python快速教程 - numpy和Matplotlib篇



PIL/Pillow

PIL:Python Imaging Library,已经是Python平台事实上的图像处理标准库了。


Pillow 是 PIL的对Python3支持的另外一个分支,当然他对Python2也兼容,由于PIL安装起来比较烦,而使用pip可以很轻松的安装Pillow,所以我选择Pillow使用,但是其核心还是PIL库的。


4. 开始

好了,奠基石和肩膀都已经准备好了,上车!

  1. #-*-coding:utf-8-*-


  2. import itchat

  3. import re

  4. import os

  5. import matplotlib as mpl

  6. from matplotlib import pyplot as plt

  7. import numpy as np

  8. import PIL.Image as Image

  9. from os import listdir

  10. import math


  11. plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签

  12. plt.rcParams['axes.unicode_minus']=False #用来正常显示负号

  13. zhfont = mpl.font_manager.FontProperties(fname='E:\PythonWorkSpace\WeChat\msyh.ttf', size=14)


有时候不得不说说外国的月亮比较圆啊。
使用的Matplotlib绘图是不能显示中文字符的,需要做一点小设置。
这两句:

  1. plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签

  2. plt.rcParams['axes.unicode_minus']=False #用来正常显示负号


这一句为指定字体的设置:

  1. zhfont = mpl.font_manager.FontProperties(fname='E:\PythonWorkSpace\WeChat\msyh.ttf', size=14)


关于上面的xx.tff为c盘windows下front字体包里的字体,我拷到目录下面了。


这样,我们就可以好好编程了+_+ ,想编个程序心也是蛮累的,不是在配置环境的路上,就是在改bug的路上,奈何程序员都是打不死的小强!


5. 登录

爬取目标网站的时候,看看有没有 HTML样式更友好的移动版(把自己的请求头设置成处于移动设备的状态,然后接收网站移动版。移动版是一个获取数据非常好的渠道。当有一个网页很难爬去的时候,应该去试试它的移动版。)


微信就已经是移动设备上的了,腾讯粑粑又没有开发微信的API,所以我们只能另辟蹊径!反向思维->Web端有木有!This is itChat!


使用itchat登录Web端的微信,代码很简单:

  1. itchat.auto_login(hotReload=True)


注: 传入True hotReload使得程序关闭后一定时间内也可以登录,该方法会生一个静态文件itchat.pkl,用于存储登陆的状态。即使程序关闭,一定时间内重新开启也可以不用重新扫码。


执行上面这句代码后会弹出一个Web微信登录的二维码QR,拿手机微信扫一扫后有以下显示:


这样就登录成功了!好简单有木有!用大神的包就是好,自己写模拟登陆的话还得抓包,分析报头,然后模拟登录。itchat简直良心到想哭。>_<


6. 获取好友信息

  1. friends = itchat.get_friends(update=True)

  2. # 爬取好友的相关信息,返回json文件

上面这个json文件就包括了微信好友的信息。


7. 好友性别

直接上代码

  1. def friend_analysis(friends):

  2.       labels = ['男', '女', '其他']

  3.       data = [0, 0, 0]


  4.       # friends[0] 是自己的信息

  5.       for friend in friends[1:]:

  6.            sex = friend["Sex"]

  7.            if sex == 1:

  8.                 data[0] += 1

  9.            elif sex == 2:

  10.                 data[1] += 1

  11.            else:

  12.                 data[2] += 1


  13.     fig = plt.figure()

  14.     plt.pie(data, labels=labels,autopct="%.2f%%")

  15.     plt.title("微信好友分析",fontsize=18,fontproperties=zhfont)

  16.     plt.show()


labels是我们要画的饼图的标注。


男、女和其他性别的提取很简单了,当然需要注意的是如果没有我们准备阶段对于Matplotlib绘图的中文字符的处理,画出来的图是显示不了汉字滴!


运行结果:

看来我的微信好友男女差不多是1:1吧,还有那5.31%不知性别的好友,他们可能对性别的要求并不是那么严格吧,毕竟人与人也没那么多的隔阂是不是 =_*


8. 区域分析

关于这个,自己之前写了一个简单的省份分析,就是从friends里去匹配Province,但是画的太丑了。所以,又找到一个“肩膀”。

  1. # extract the variables: NickName, Sex, City, Province, Signature

  2. def get_features(friends):

  3.       features = []

  4.       for friend in friends:

  5.            feature = {'NickName': friend['NickName'], 'Sex': friend['Sex'], 'City': friend['City'],'Province': friend['Province'], 'Signature': friend['Signature']}

  6.           features.append(feature)

  7.       return pd.DataFrame(features)

  8. features = get_features(friends[1:])

  9. print(features.columns)

  10. features.head()

  11. locations = features.loc[:, ['Province', 'City']]  # get location columns

  12. locations = locations[locations['Province'] != '']  # clean empty city or province records

  13. data = locations.groupby(['Province', 'City']).size().unstack()  # group by and count

  14. count_subset = data.take(data.sum(1).argsort())[-20:]  # obtain the 20 highest data


  15. # plot

  16. subset_plot = count_subset.plot(kind='bar', stacked=True, figsize=(24, 24))


  17. # set fonts

  18. xtick_labels = subset_plot.get_xticklabels()

  19. for label in xtick_labels: 

  20.      label.set_fontproperties(font)

  21. legend_labels = subset_plot.legend().texts

  22. for label in legend_labels:

  23.      label.set_fontproperties(font) 

  24.      label.set_fontsize(10)


  25. plt.xlabel('Province', fontsize=20)

  26. plt.ylabel('Number', fontsize=20)

  27. plt.show()


上面这段代码更是厉害,提取了昵称,性别, 城市, 省份, 签名。
我只用他的省市画图部分locations,结果如下;


emmmm,放不大了,全图看不到,而且放大拖动起来巨卡,这个图也是辛苦了i3了。


从上面可以看到,我大陕西的乡党们在哪里!!我大西安的乡党们在哪里!!


排名第二、三的北京和广东,就是那群在北(上?)广深那一波人吧,向他们致敬!


从排名第四开始,某种程度上可以说是在陕西的各省学霸的分布了吧!尤其是河北、河南、山东!这些省份的同学一直都是学神一样的存在,陕西欢迎你们,学生生涯请轻虐+_+


9. 签名

  1. def signature_analysis(friends):

  2.       signature_list = list()


  3.       for friend in friends[1:]:

  4.            signature = friend['Signature'].strip()

  5.            signature_list.append(signature)

  6.            print(friend['NickName'] + "\t" + signature)


这是从friends中分析出好友签名的,.strip()是用来删除空白符。


最后的输出是打印出昵称+签名。这个比较隐私就不展示了哈。有时间的还可以整理下这些签名,使用jieba分词+Wordcloud云词生成一个图片。


10. 获取好友头像

  1. def getImage(friends):

  2.       #下载所有好友的头像图片

  3.       num = 0

  4.       for i in friends:

  5.         img = itchat.get_head_img(i["UserName"])

  6.         with open('./headImg/' + str(num) + ".png",'wb') as f:

  7.         f.write(img)

  8.         f.close()

  9.         num += 1

  10.       #获取文件夹内的文件个数

  11.       length = len(os.listdir('./headImg'))

  12.       #根据总面积求每一个的大小

  13.       each_size = int(math.sqrt(float(810*810)/length))

  14.        #每一行可以放多少个

  15.        lines = int(810/each_size)

  16.        #生成白色背景新图片

  17.        image = Image.new('RGBA', (810, 810),'white')

  18.         x = 0

  19.         y = 0

  20.         for i in range(0,length):

  21.           try:

  22.             img = Image.open('./headImg/' + str(i) + ".png")

  23.           except IOError:

  24.            print(i)

  25.            print("Error")

  26.           else:

  27.             img = img.resize((each_size, each_size), Image.ANTIALIAS) #resize 

  28.             image with high-qualityimage.paste(img, (x * each_size, y * each_size))

  29.            x += 1

  30.            if x == lines:

  31.               x = 0

  32.               y += 1

  33.            image.save('./headImg/' + "all.png")

  34.            #通过文件传输助手发送到自己微信中

  35.            itchat.send_image('./headImg/' + "all.png",'filehelper')

  36.            image.show()


注释里写的应该算很清楚,需要注意的是:
开始想截取好友头像图片遇到了一个报错:

  1. cannot write mode rgba as jpg


google后如下:


这是因为,JPG只有三个通道,而程序中一定用到了RGBA四个通道,所以程序不知道多出来的一个通道怎么处理,就会报错了。


解决如下:


  1. PNG图像有RGBA四个通道,而BMP和JPG图像只有RGB三个通道,所以我们可以将程序中所有图片的保存形式改为PNG.(本文采用的是这种方法。)

        

  2. 不想改变图片格式,就添加判断,进行转换

  1. if len(toImage.split())==4:

  2.    r,g,b,a=toImage.split()        #利用split和merge将通道从四个转换为三个

  3.    toImage=Image.merge("RGB",(r,g,b))

  4.    toImage.save(user + ".jpg")


“全世界的程序员们联合起来,那些bug的坑我们填一个它就少一个!”


结果:


来来来,找自己,找到三个自己就可以Bingo了…


11. 最后,人生苦短,且行且珍惜

强烈建议仅使用小号(小号怎么会有好友?反正我给你们建议了…日后可不要搞个大新闻把我批判一番)


小道消息:从近期 (17年6月下旬)反馈来看,使用itchat及其他微信机器人(类爬虫程序)存在一定概率被限制登录的可能性。主要表现为无法登陆 Web 微信 (但不影响手机等其他平台)。


现在感觉都是爬一次少一次,Web微信有时候也登不上去+_+,前几天还被封号两天,微信消息只能看,不能回复,朋友圈不能评论,不能点赞,这对一个话痨来说简直就是无声的摧残!


12. 最后的最后,反思

微信是不是太强大了,生活、学习、工作中真的是一分一秒都离不开!所以,还是建议大家时不时的用下QQ,用下微博,多和新老好友们尬聊下,不然,真到了微信垄断那一天,你我联系只能靠漂流瓶了!全看缘分!


文章作者:肖洒

原文链接:https://x-nicolo.github.io/2017/10/23/Python%E5%BE%AE%E4%BF%A1%E5%A5%BD%E5%8F%8B%E5%88%86%E6%9E%90/#more


图文编辑:西电青苔工作室 甄少华

网页编辑:西电青苔工作室 甄少华



关注我们

想获取互联网干货

请扫描下方二维码


Copyright © 南京音乐推荐联合社@2017