├── Images ├── change.png ├── changedetails.png ├── cloud.png ├── reigon.png └── sex.png ├── README.md ├── activityRate.py ├── analyzeData.py ├── autoDownload.py ├── bot.py ├── getLatestData.py ├── groupBot.py ├── provinceMap.py ├── sex.py ├── signUp.py ├── transfer_single.py └── wordCloud.py /Images/change.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tenkeyseven/wechatGroupAnalyzer/161159d4c6e32a6f3d25b9152b49749b7f7cfeb0/Images/change.png -------------------------------------------------------------------------------- /Images/changedetails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tenkeyseven/wechatGroupAnalyzer/161159d4c6e32a6f3d25b9152b49749b7f7cfeb0/Images/changedetails.png -------------------------------------------------------------------------------- /Images/cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tenkeyseven/wechatGroupAnalyzer/161159d4c6e32a6f3d25b9152b49749b7f7cfeb0/Images/cloud.png -------------------------------------------------------------------------------- /Images/reigon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tenkeyseven/wechatGroupAnalyzer/161159d4c6e32a6f3d25b9152b49749b7f7cfeb0/Images/reigon.png -------------------------------------------------------------------------------- /Images/sex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tenkeyseven/wechatGroupAnalyzer/161159d4c6e32a6f3d25b9152b49749b7f7cfeb0/Images/sex.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 微信群分析器 2 | 3 | `python 3.6` `itchat` `pyecharts` `jieba` 4 | 5 | ## Update 6 | - 「2019/11/6」由于微信网页版登陆出现限制,此项目可能出现**无法登录**问题,相关问题移步 [littlecodersh/ItChat](https://github.com/littlecodersh/ItChat) Issue 区域查看 7 | 8 | ## 实现功能 9 | 10 | ### 1.群聊人员增减分析 11 | 12 | #### 增减数量图 13 | 14 | ![](https://github.com/tenkeyseven/wechatGroupAnalyzer/blob/master/Images/change.png) 15 | 16 | #### 具体情况输出 17 | 18 |
19 | 20 |
21 | 22 | ### 2.生成群成员三图(地区分布图、签名词云图、性别比例图) 23 | 24 | #### 地区分布图 25 | 26 | 27 | 28 | ![](https://github.com/tenkeyseven/wechatGroupAnalyzer/blob/master/Images/reigon.png) 29 | 30 | #### 群成员签名词云图 31 | 32 | 33 | 34 | ![](https://github.com/tenkeyseven/wechatGroupAnalyzer/blob/master/Images/cloud.png) 35 | 36 | #### 群成员性别比例图 37 | 38 | 39 | 40 | ![](https://github.com/tenkeyseven/wechatGroupAnalyzer/blob/master/Images/sex.png) 41 | 42 | ## 使用说明 43 | 44 | 基于`python3.6`环境开发,使用了微信端第三方 Api 库`itchat`,echarts 的 python 接口库`pyecharts`, 分词库`jieba`,以及其他一些在程序工作中要用到了编解码、存储等库。 45 | 46 | 安装方法: 47 | 48 | ``` 49 | pip install itchat 50 | pip install pyecharts 51 | pip install jieba 52 | ``` 53 | 54 | 此分析器包含两个 python 程序,分别为 getLatestData.py 和 analyzeData.py 。 55 | 56 | getLatestData.py 用于对指定的群列表获取最新的群成员信息,并写入文件保存。 57 | 58 | analyzeData.py 用于对指定的群列表进行分析,输出群成员变化细则、群成员人数增减图和三图(群成员分布图、群成员签名云图和群成员性别比例图) 59 | 60 | ### 使用流程 61 | 62 | 1. 在手机上确定要分析的群聊,点开设置,将群聊保存至通讯录(Save to Contacts)。 63 | 2. 运行 getLatestData.py,第一次登陆,会弹出二维码,使用手机扫码登陆微信网页版,并确认,之后登陆只需要在手机确认即可。 64 | 3. 程序将会自动生成文件夹result,并将原始数据保存至此。 65 | 4. 运行 analyzeData.py,程序将会对数据进行分析,输出分许结果以及生成相应的图。 66 | 67 | ### 参数说明 68 | 69 | 在 getLatestData.py 中,参数设置如下 70 | 71 | ```python 72 | #getLatestData.py 73 | if __name__ == '__main__': 74 | '''在GroupList中输入想要分析的群聊名称,输入login的参数 75 | login = 'auto',会调用itchat的自动缓存登陆模式,第二次登陆无需扫码 76 | 适用于持续使用者 77 | logn = 'single',会调用itchat单次扫码登陆模式,适合于一次使用。 78 | ''' 79 | GroupList = ['测试','计算机网络2018'] 80 | introduce() 81 | init() 82 | mainWork( 83 | GroupList, 84 | login = 'auto' 85 | ) 86 | ``` 87 | 88 | 89 | 90 | 在 analyzeData.py 中,参数设置应如下 91 | 92 | ```python 93 | #analyzeData.py 94 | if __name__ == '__main__': 95 | '''在GroupList中添加需要分析的群名 96 | 在main函数中相应添加True/False值来确定是否要进行绘制 地理分布图、词云图和性别饼图 97 | 三个值默认都为True 98 | 对群成员的分析默认进行绘图。 99 | ''' 100 | GrouppList = ['测试','计算机网络2018'] 101 | main( 102 | GrouppList, 103 | Map = True, #True 或 默认 为开启画图,False为不开启 104 | Cloud = True, 105 | Pie = True 106 | ) 107 | ``` 108 | 109 | ### 其他 110 | 111 | 对群成员人数增减进行分析依赖于多次采集的数据,而绘制三图相对不受人员变化影响,所以可以在第一次三图绘制好之后,将其设置为False,每次分析数据只分析人员变化。 112 | 113 | ### 参考内容 114 | 115 | + [pyecharts](https://github.com/pyecharts/pyecharts) 116 | + [itchat](https://github.com/littlecodersh/ItChat) 117 | + [CSDN:利用itchat接口进行微信好友数据分析](https://blog.csdn.net/alicelmx/article/details/80862340) 118 | 119 | ### 其他内容 120 | 121 | --- 122 | 123 | ![](https://img.shields.io/badge/Tenkeyseven-(%20%E2%80%A2%CC%80%20%CF%89%20%E2%80%A2%CC%81%20)%E2%9C%A7-green.svg)一些小例子 124 | 125 | #### 1.微信好友的词云图 126 | 127 | **依赖库安装** 128 | 129 | `pip install itchat` 130 | 131 | `pip install pyecharts` 132 | 133 | **运行代码** 134 | 135 | [有注释的代码](https://github.com/tenkeyseven/wechatGroupAnalyzer/blob/master/wordCloud.py) 136 | 137 | 138 | 139 | #### 2.微信好友性别比 140 | 141 | **依赖库安装** 142 | 143 | `pip install itchat` 144 | 145 | `pip install pyecharts` 146 | 147 | **运行代码** 148 | 149 | [有注释的代码](https://github.com/tenkeyseven/wechatGroupAnalyzer/blob/master/sex.py) 150 | 151 | 152 | 153 | #### 3.微信好友地区分布图 154 | 155 | **使用** 156 | 157 | 和以上两种一样,运行后会自动在程序根目录生成.html电子图 158 | 159 | **依赖库安装** 160 | 161 | `pip install itchat` 162 | 163 | `pip install pyecharts` 164 | 165 | `pip install echarts-countries-pypkg `(安装必要的地图 166 | 167 | **运行代码** 168 | 169 | [代码](https://github.com/tenkeyseven/wechatGroupAnalyzer/blob/master/provinceMap.py) 170 | 171 | 172 | 173 | 174 | 175 | #### 4.图灵小机器人私戳版(不是很图灵...) 176 | **依赖库安装** 177 | 178 | `pip install itchat` 179 | 180 | **运行代码** 181 | 182 | [bot.py的代码](https://github.com/tenkeyseven/wechatGroupAnalyzer/blob/master/bot.py) 183 | 184 | 185 | 186 | #### 5.图灵小机器人群聊版(不是那么图灵+1) 187 | 188 | **使用** 189 | 190 | 运行程序,在群里@机器人并且带消息,然后机器人就会在群里自动回复你了~ 191 | 192 | **依赖库安装** 193 | 194 | `pip install itchat` 195 | 196 | **运行代码** 197 | 198 | [群聊版代码](https://github.com/tenkeyseven/wechatGroupAnalyzer/blob/master/groupBot.py) 199 | 200 | 201 | 202 | #### 6.非常简单的群聊文件自动下载工具 203 | 204 | **使用** 205 | 206 | 运行程序,然后此程序自动下载微信群中别人发的文件。 207 | 208 | **依赖库安装** 209 | 210 | `pip install itchat` 211 | 212 | **运行代码** 213 | 214 | [代码](https://github.com/tenkeyseven/wechatGroupAnalyzer/blob/master/autoDownload.py) 215 | 216 | 217 | 218 | #### 7.微信消息转发器v1 219 | 220 | **使用** 221 | 222 | 【例】微信转发消息工具,转发指定群个人消息至另外一群 223 | 224 | 例如: 225 | 226 | ​ --在群聊A中,小T发消息:你好 227 | 228 | ​ --在群聊B中有转发消息:及时收到来自群聊【A】,@小T的消息:你好 229 | 230 | 使用: 231 | 232 | ​ --运行本程序即可,关闭退出即可 233 | 234 | 说明: 235 | 236 | ​ --目前仅限于接收和转化文本消息,图片、语音、视频、文件暂时未添加功能。 237 | 238 | **依赖库安装** 239 | 240 | `pip install itchat` 241 | 242 | **运行代码** 243 | 244 | [有注释的代码](https://github.com/tenkeyseven/wechatGroupAnalyzer/blob/master/transfer_single.py) 245 | 246 | 247 | 248 | #### 8.微信群报名小助手 249 | 250 | **使用** 251 | 252 | 【例子】微信报名签到小工具 253 | 254 | 使用: 255 | 256 | ​ 在微信群中,@<签到管理器>报名,即时返回签到信息 257 | 258 | 例子: 259 | 260 | > 小A:@小T 报名 261 | 262 | > 小T:收到,目前报名人有 263 | 264 | > ​ 1.小A 265 | 266 | **依赖库安装** 267 | 268 | `pip install itchat` 269 | 270 | **运行代码** 271 | 272 | [有注释的代码](https://github.com/tenkeyseven/wechatGroupAnalyzer/blob/master/signUp.py) 273 | -------------------------------------------------------------------------------- /activityRate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | 【例子】发言热度 6 | 7 | """ 8 | 9 | import itchat 10 | from itchat.content import TEXT 11 | 12 | from collections import Counter 13 | 14 | from pyecharts import Bar 15 | 16 | import time 17 | 18 | @itchat.msg_register(TEXT, isGroupChat=True) 19 | def statistics(msg): 20 | if msg['FromUserName'] == groupID: 21 | print('{}发言了:{}'.format(msg['ActualNickName'], msg['Text'])) 22 | talkCounter[msg['ActualNickName']] += 1 23 | print(talkCounter) 24 | 25 | if __name__ == '__main__':s 26 | itchat.auto_login(hotReload=True) 27 | groupName = '啊哈' 28 | groupID = itchat.search_chatrooms(name=groupName)[0]['UserName'] 29 | 30 | talkCounter = Counter() 31 | beginTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) 32 | itchat.run() 33 | endTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) 34 | 35 | duration = '统计自 {} 到 {} 时间段内'.format(beginTime, endTime) 36 | 37 | bar = Bar(title='{}群活跃度表'.format(groupName), subtitle=duration, width=1200, height=600, title_pos='left') 38 | attr, value = bar.cast(talkCounter.most_common(100)) 39 | bar.add( 40 | '', attr, value, 41 | xaxis_name='昵称', 42 | yaxis_name='发言活跃度', 43 | is_label_show = True, 44 | is_datazoom_show = True, 45 | datazoom_type = 'both', 46 | xaxis_name_pos = 'end' 47 | ) 48 | bar.render('./{}发言活跃度.html'.format(groupName)) -------------------------------------------------------------------------------- /analyzeData.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | import codecs 5 | import datetime 6 | import json 7 | from pyecharts import Bar 8 | from collections import Counter 9 | from pyecharts import Bar,Pie,Map,WordCloud 10 | import jieba.analyse 11 | import re 12 | import os 13 | 14 | def getFiles(inputFile): 15 | with codecs.open(inputFile,encoding='utf-8') as f: 16 | friendsList = json.load(f) 17 | return friendsList 18 | 19 | def get_var(var,mlist): 20 | variable = [] 21 | for i in mlist: 22 | value = i[var] 23 | variable.append(value) 24 | return variable 25 | 26 | def peopledic(add,quit): 27 | dict_temp = { 28 | 'add' : [], 29 | 'quit' : [] 30 | } 31 | dict_temp['add'] = add 32 | dict_temp['quit'] = quit 33 | return dict_temp 34 | 35 | def getSelectedList(mlist,groupName): 36 | selectedList = [] 37 | for rawGroup in mlist: 38 | if rawGroup['name'] == groupName: 39 | selectedList.append(rawGroup) 40 | return selectedList 41 | 42 | def getAddQuitList(mlist): 43 | addlist = [[]] 44 | quitlist =[[]] 45 | lens = len(mlist) 46 | for i in range(lens): 47 | addlist.append(mlist[i]['add']) 48 | quitlist.append(mlist[i]['quit']) 49 | return addlist,quitlist 50 | 51 | def getLenofList(addlist,quitlist): 52 | lenaddlist = [] 53 | lenquitlist = [] 54 | 55 | for i in addlist: 56 | lenaddlist.append(len(i)) 57 | 58 | for i in quitlist: 59 | lenquitlist.append(len(i)) 60 | return lenaddlist,lenquitlist 61 | 62 | def drawBar(timeList,amountList,markdictList,name): 63 | outputFile='./result/{}_群人员变化表.html'.format(name) 64 | addlist,quitlist = getAddQuitList(markdictList) 65 | lenaddlist,lenquitlist = getLenofList(addlist,quitlist) 66 | 67 | bar = Bar('{} 群人员变化表'.format(name),width = 1200, height = 600, title_pos = 'left') 68 | bar.add( 69 | '群总人数', 70 | timeList,amountList, 71 | tooltip_tragger = 'item', 72 | tooltip_tragger_on ='mousemove|click', 73 | is_label_show = True, 74 | ) 75 | bar.add( 76 | '较前一时间入群人数', 77 | timeList,lenaddlist, 78 | is_label_show = True, 79 | 80 | ) 81 | bar.add( 82 | '较前一时间退群人数', 83 | timeList,lenquitlist, 84 | xaxis_name = '检测群时间', 85 | yaxis_name = '群人数', 86 | label_color = ['#8A2BE2','#EE2C2C','#7CFC00'], 87 | is_label_show = True, 88 | is_datazoom_show = True, 89 | datazoom_type = 'both', 90 | xaxis_label_textsize = '10', 91 | xaxis_type = 'category' 92 | ) 93 | 94 | bar.render(outputFile) 95 | 96 | def analyseProvince(mlist): 97 | '''use this function to get provinceinfo''' 98 | provinceCounter = Counter() 99 | for province in mlist: 100 | if province != '': 101 | provinceCounter[province] += 1 102 | return provinceCounter 103 | 104 | def extractTag(text,tagsList): 105 | if text: 106 | tags = jieba.analyse.extract_tags(text) 107 | 108 | for tag in tags: 109 | tagsList[tag] += 1 110 | 111 | def analyseSignature(mlist): 112 | signatureCounter = Counter() 113 | for signature in mlist: 114 | signature = signature.strip().replace("emoji", "").replace("span", "").replace("class", "") 115 | rec = re.compile("1f\d+\w*|[<>/=]") 116 | signature = rec.sub("", signature) 117 | extractTag(signature,signatureCounter) 118 | return signatureCounter 119 | 120 | def analyseSexInfo(mlist): 121 | '''This function accepet an sex list and return the statistics in tuple''' 122 | male = 0 123 | female = 0 124 | unknownsex = 0 125 | for sex in mlist: 126 | if sex == 1: 127 | male += 1 128 | elif sex == 2: 129 | female += 1 130 | else: 131 | unknownsex += 1 132 | return (male,female,unknownsex) 133 | 134 | def counter2list(_counter): 135 | nameList,countList = [],[] 136 | for counter in _counter: 137 | nameList.append(counter[0]) 138 | countList.append(counter[1]) 139 | return (nameList,countList) 140 | 141 | def drawMap(name,rank,chatroomname): 142 | outputFile = './result/{}_群成员区域分布图.html'.format(chatroomname) 143 | map = Map(title='{} 群成员区域分布图'.format(chatroomname), width=1200, height=600, title_pos='center') 144 | map.add( 145 | '',name,rank, 146 | maptype = 'china', # 地图范围 147 | is_visualmap = True, # 是否开启鼠标缩放漫游等 148 | is_label_show = True, # 是否显示地图标记 149 | ) 150 | map.render(outputFile) 151 | 152 | def drawWorldCloud(name,rank,chatroomname): 153 | outputFile = './result/{}_群成员签名词云图.html'.format(chatroomname) 154 | cloud = WordCloud('{} 群成员签名词云图'.format(chatroomname), width=1200, height=600, title_pos='center') 155 | cloud.add( 156 | ' ',name,rank, 157 | shape='star', 158 | background_color='white', 159 | max_words=200 160 | ) 161 | cloud.render(outputFile) 162 | 163 | def drawPie(name,rank,chatroomname): 164 | outputFile = './result/{}_群性别比例图.html'.format(chatroomname) 165 | pie = Pie('{} 群性别比例图'.format(chatroomname), width=1200, height=600, title_pos='center') 166 | pie.add( 167 | '', 168 | name,rank, 169 | is_label_show = True, # 是否显示标签 170 | label_text_color = None, # 标签颜色 171 | legend_orient = 'vertical', # 图例是否垂直 172 | legend_pos = 'left' 173 | ) 174 | pie.render(outputFile) 175 | 176 | def analyseGroupByName(selectedList,name): 177 | nickNameListSet = [] 178 | remarkNameListSet = [] 179 | amountList = [] 180 | timeList = [] 181 | markdictList = [] 182 | 183 | for x in selectedList: 184 | nickNameListSet.append(get_var(var = 'NickName', mlist = x['record'])) 185 | remarkNameListSet.append(get_var(var = 'RemarkName', mlist = x['record'])) 186 | 187 | lenofSelectedList = len(selectedList) #this is the len of the name corresponding GrouppList 188 | 189 | for x in range(lenofSelectedList): 190 | timeList.append(selectedList[x]['time']) 191 | amountList.append(len(nickNameListSet[x])) 192 | 193 | ''' this loop are use to generate a list containing dictionary of the add/quit info 194 | ''' 195 | for i in range(lenofSelectedList-1): # the amount of stored groups' all data block 196 | quitlist = [] 197 | addlist =[] 198 | for j in range(amountList[i]): 199 | if nickNameListSet[i][j] in nickNameListSet[i+1]: 200 | pass 201 | else: 202 | quitlist.append(nickNameListSet[i][j]) 203 | 204 | for j in range(amountList[i+1]): 205 | if nickNameListSet[i+1][j] in nickNameListSet[i]: 206 | pass 207 | else: 208 | addlist.append(nickNameListSet[i+1][j]) 209 | 210 | markdictList.append(peopledic(add = addlist,quit = quitlist)) 211 | 212 | print('------------------------分析开始------------------------\n') 213 | drawBar(timeList,amountList,markdictList,name) 214 | print("{} 群分析完成!".format(name)) 215 | info = '截至目前一共采集了{}组数据'.format(lenofSelectedList) 216 | print(info) 217 | info2 = '人员增减变化、地区分布、词云图、性别比的图表已经生成了,在本文件目录result文件夹下可以找到,接下来给出具体增减成员信息\n' 218 | print(info2) 219 | 220 | addlist,quitlist = getAddQuitList(markdictList) 221 | lenaddlist,lenquitlist = getLenofList(addlist,quitlist) 222 | 223 | for i in range(lenofSelectedList): 224 | print("时间:{}\n群总人数 {}".format(timeList[i],amountList[i])) 225 | if lenaddlist[i] != 0: 226 | print("群成员相较于前一次增加了{}人,分别为: ".format(lenaddlist[i])) 227 | for j in range(len(addlist[i])): 228 | print(addlist[i][j], end = ' ') 229 | else: 230 | print("群成员相较于前一次没有增加") 231 | if lenquitlist[i] != 0: 232 | print("\n群成员相较于前一次减少了{}人,分别为: ".format(lenquitlist[i])) 233 | for j in range(len(quitlist[i])): 234 | print(quitlist[i][j], end = ' ') 235 | else: 236 | print("\n群成员相较于前一次没有减少") 237 | print('\n') 238 | print('------------------------分析结束------------------------\n') 239 | 240 | def drawThreeGraphies(selectedList, name, Map, Cloud, Pie): 241 | 242 | lenofSelectedList = len(selectedList) 243 | LatestIndex = lenofSelectedList - 1 244 | 245 | nickNameList = get_var(var = 'NickName', mlist = selectedList[LatestIndex]['record']) 246 | # remarkNameList = get_var(var = 'RemarkName', mlist = selectedList[LatestIndex]['record']) 247 | provinceList = get_var(var = 'Province', mlist = selectedList[LatestIndex]['record']) 248 | # cityList = get_var(var = 'City', mlist = selectedList[LatestIndex]['record']) 249 | sexList = get_var(var = 'Sex', mlist = selectedList[LatestIndex]['record']) 250 | signatureList = get_var(var = 'Signature', mlist = selectedList[LatestIndex]['record']) 251 | 252 | total = len(nickNameList) 253 | 254 | # for i in range(total): 255 | # print("{}({}) {} {}{} {}".format(nickNameList[i],remarkNameList[i],provinceList[i],cityList[i],sexList[i],signatureList[i])) 256 | 257 | if Map : 258 | provinceCounter = analyseProvince(provinceList) 259 | nameList,ranklist = counter2list(provinceCounter.most_common(15)) 260 | drawMap(nameList,ranklist,name) 261 | else: 262 | pass 263 | 264 | if Cloud : 265 | signatureCounter = analyseSignature(signatureList) 266 | nameList,ranklist = counter2list(signatureCounter.most_common(200)) 267 | drawWorldCloud(nameList,ranklist,name) 268 | else: 269 | pass 270 | 271 | if Pie: 272 | sextuple = analyseSexInfo(sexList) 273 | nameList = ['男','女','未标记'] 274 | ranklist = [] 275 | for i in sextuple: 276 | ranklist.append(i) 277 | drawPie(nameList,ranklist,name) 278 | else: 279 | pass 280 | 281 | def main(GrouppList, Map = True, Cloud = True, Pie = True): 282 | print("analysing...Please wait a little while") 283 | inputfiles = './result/records.json' 284 | if os.path.exists(inputfiles) != True: 285 | print("Program has stopped, Please make sure data file exists and be in right path") 286 | return 287 | dataList = getFiles(inputfiles) 288 | searchGroupList = GrouppList 289 | 290 | for group in searchGroupList: 291 | selectedList = getSelectedList(mlist = dataList, groupName = group) 292 | drawThreeGraphies(selectedList = selectedList, name = group, Map = Map, Cloud = Cloud, Pie = Pie) 293 | analyseGroupByName(selectedList = selectedList, name = group) 294 | 295 | if __name__ == '__main__': 296 | '''在GroupList中添加需要分析的群名 297 | 在main函数中相应添加True/False值来确定是否要进行绘制 地理分布图、词云图和性别饼图 298 | 三个值默认都为True 299 | 对群成员的分析默认进行绘图。 300 | ''' 301 | GrouppList = ['pyecharts 可视化交流群','测试','计算机网络2018'] 302 | main( 303 | GrouppList, 304 | Map = True, #True 或 默认 为开启画图,False为不开启 305 | Cloud = True, 306 | Pie = True 307 | ) -------------------------------------------------------------------------------- /autoDownload.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import itchat 5 | 6 | @itchat.msg_register([itchat.content.ATTACHMENT], isGroupChat=True) 7 | def auto_download(msg): 8 | print(msg) 9 | msg.download(msg.fileName) 10 | sender = itchat.search_friends(userName=msg.fromUserName) 11 | print('get {} from {} sucessfully'.format(msg.fileName, sender.nickName)) 12 | return 13 | 14 | itchat.auto_login(hotReload=True) 15 | itchat.run() 16 | -------------------------------------------------------------------------------- /bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import itchat 5 | import requests 6 | 7 | KEY = 'd6adf489248347428178a7bbff5502a7' 8 | 9 | def get_response(msg): 10 | apiUrl = 'http://www.tuling123.com/openapi/api' 11 | data = { 12 | 'key' : KEY, 13 | 'info' : msg, 14 | 'userid' : 'wechat-robot', 15 | } 16 | 17 | try: 18 | r = requests.post(apiUrl, data=data).json() 19 | return r.get('text') 20 | except: 21 | return 22 | 23 | @itchat.msg_register(itchat.content.TEXT) 24 | def tuling_reply(msg): 25 | defaultReply = '我收到你的消息啦,让我想想~' 26 | reply = get_response(msg['Text']) 27 | return reply or defaultReply 28 | 29 | itchat.auto_login(hotReload=True) 30 | itchat.run() 31 | -------------------------------------------------------------------------------- /getLatestData.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | import itchat 5 | import codecs 6 | import json 7 | import datetime 8 | import os 9 | 10 | def introduce(): 11 | intro = ''' 12 | welcome to use this program to know your wechat groups 13 | we can use this program to 14 | 1.Know how many people are in this group and who are they. 15 | 2.Get visible data in sex ratio, local distribution and signature wordcloud. 16 | 3.if run full time, maybe it can get the real time monitoring on group members. 17 | PLEASE MAKE SURE THAT YOU SAVE THIS GROUPCHAT TO YOUR CONTACT 18 | ''' 19 | print(intro) 20 | intro_begin = 'OK, program is ready to work, this may take a little while.\n' 21 | print(intro_begin) 22 | 23 | 24 | def saveFiles(friendsList): 25 | outputFile = './result/records.json' 26 | with codecs.open(outputFile,'w',encoding='utf-8') as jsonFile: 27 | # 默认使用ascii,为了输出中文将参数ensure_ascii设置成False 28 | jsonFile.write(json.dumps(friendsList,ensure_ascii=False)) 29 | 30 | def getFiles(inputFile): 31 | with codecs.open(inputFile,encoding='utf-8') as f: 32 | friendsList = json.load(f) 33 | return friendsList 34 | 35 | def get_var(var,mlist): 36 | variable = [] 37 | for i in mlist: 38 | value = i[var] 39 | variable.append(value) 40 | return variable 41 | 42 | def getTime(): 43 | return datetime.datetime.now().strftime('%Y-%m-%d|%H:%M:%S') 44 | 45 | def generateDict(mlist,name): 46 | currentTime = getTime() 47 | 48 | currentDict ={ 49 | 'time' : currentTime, 50 | 'name' : name, 51 | 'record' : mlist 52 | } 53 | 54 | return currentDict 55 | 56 | def saveData(saveddict): 57 | filesAddress = './result/records.json' 58 | data = getFiles(filesAddress) 59 | data.append(saveddict) 60 | print("Save data sucessfully!") 61 | print("we have already saved {} data block\n".format(len(data))) 62 | saveFiles(data) 63 | 64 | def makedir(folderAddress): 65 | if os.path.exists(folderAddress): 66 | pass 67 | else: 68 | os.makedirs(folderAddress) 69 | 70 | def init(): 71 | makedir('./result') 72 | 73 | init_list = [] 74 | 75 | if os.path.exists('./result/records.json'): 76 | pass 77 | else: 78 | saveFiles(init_list) 79 | 80 | def mainWork(chatRoomList,login): 81 | 82 | if login == 'auto': 83 | itchat.auto_login(hotReload = True) 84 | elif login == 'single': 85 | ichat.login() 86 | else: 87 | print("[Stopped] plz input correct login command") 88 | return 89 | 90 | for chatRoomName in chatRoomList: 91 | searchedChatRoomList = itchat.search_chatrooms(chatRoomName) 92 | ''' Try to search the matched chatrooms ''' 93 | ''' ''' 94 | if searchedChatRoomList is None: 95 | print("{} is not founded".format(chatRoomName)) 96 | elif len(searchedChatRoomList) is 0: 97 | print("Oh No, We got nothing, ** Make sure that you save this groupchat to contact **") 98 | else: 99 | ''' get the chatroom ''' 100 | # print(searchedChatRoomList) 101 | thisUserName = searchedChatRoomList[0]["UserName"] 102 | # print(thisUserName) #get the "id" UserName 103 | 104 | chatRoom = itchat.update_chatroom(thisUserName, detailedMember=True) #update the group message,and then return the chatroom 105 | # print(chatRoom['MemberList']) 106 | total = len(chatRoom['MemberList']) #get the len of chatroom memberlist 107 | 108 | currentSavedDict = generateDict(chatRoom['MemberList'], chatRoomName) 109 | 110 | saveData(currentSavedDict) 111 | itchat.logout() 112 | 113 | if __name__ == '__main__': 114 | '''在GroupList中输入想要分析的群聊名称,输入login的参数 115 | login = 'auto',会调用itchat的自动缓存登陆模式,第二次登陆无需扫码 116 | 适用于持续使用者 117 | logn = 'single',会调用itchat单次扫码登陆模式,适合于一次使用。 118 | ''' 119 | GroupList = ['测试','计算机网络2018'] 120 | introduce() 121 | init() 122 | mainWork( 123 | GroupList, 124 | login = 'auto' 125 | ) -------------------------------------------------------------------------------- /groupBot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | 【例】图灵小机器人的群聊版 6 | 功能: 7 | 开启后,在群里@机器人并带上消息,机器人会在群聊里@提问者并回复 8 | 机器人回复内容来自 http://www.tuling123.com/openapi/api, 9 | KEY值是使用api的通行证,可以自己申请。 10 | 11 | """ 12 | 13 | import itchat 14 | import requests 15 | 16 | def get_response(info): 17 | ''' 18 | 此函数用于调用API获取回复,若出现问题时,将会返回一个空值 19 | ''' 20 | apiUrl = 'http://www.tuling123.com/openapi/api' 21 | data = { 22 | 'key' : KEY, 23 | 'info' : info, 24 | 'userid' : 'wechat-robot', 25 | } 26 | 27 | try: 28 | r = requests.post(apiUrl, data=data).json() 29 | return r.get('text') 30 | except: 31 | return 32 | def getReply(text): 33 | ''' 34 | 此函数用于群里@机器人后消息的处理,处理除去@<机器人名>后的文本消息 35 | ''' 36 | if text == '': 37 | return '@机器人的同时说些什么吧~' 38 | defalutReply = '机器人开小差了等会儿再试试吧' 39 | reply = get_response(text) 40 | return reply or defalutReply 41 | 42 | @itchat.msg_register(itchat.content.TEXT, isGroupChat=True) 43 | def group_reply(msg): 44 | ''' 45 | 此函数用于接收群聊消息和回复消息,只有机器人被@之后,才做出回复 46 | 例: 47 | (在某群中) 48 | 群成员小k : @robot 你好啊 49 | robot自动回复 : @小k: 你也好呀 50 | ''' 51 | textMsg = msg['Text'] 52 | print('收到群消息:{}'.format(textMsg)) 53 | if msg.isAt: 54 | robotHostName = '@' + myself['NickName'] 55 | rawMessage = textMsg.replace(robotHostName, '') #对获取的消息做处理,将@<机器人名>从文本中去除 56 | # print('{}'.format(rawMessage)) 57 | itchat.send(u'@{}\u2005: {}'.format(msg['ActualNickName'], getReply(rawMessage)),msg['FromUserName']) 58 | 59 | if __name__ == '__main__': 60 | KEY = 'd6adf489248347428178a7bbff5502a7' 61 | itchat.auto_login(hotReload=True) #登陆微信 62 | myself = itchat.search_friends() #获取机器人账号自己的消息 63 | itchat.run() 64 | -------------------------------------------------------------------------------- /provinceMap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import itchat 5 | from pyecharts import Map 6 | from collections import Counter 7 | 8 | itchat.auto_login(hotReload=True) 9 | myFriendList = itchat.get_friends() 10 | 11 | provinceCounter = Counter() 12 | 13 | for friend in myFriendList: 14 | province = friend['Province'] 15 | if province != '': 16 | provinceCounter[province] += 1 17 | 18 | myMap = Map('你的微信好友地区分布图',width=1200, height=600, title_pos='center') 19 | attr, value = myMap.cast(provinceCounter) 20 | myMap.add( 21 | '', attr, value, 22 | maptype = 'china', 23 | is_visualmap = True, 24 | is_label_show = True, 25 | visual_range = [0,80] 26 | ) 27 | myMap.render('./你的微信好友地区分布图.html') 28 | 29 | 30 | -------------------------------------------------------------------------------- /sex.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | 【例子】分析微信好友性别比例 6 | 引入库 7 | `itchat` 模拟登陆网页版微信 8 | `pyecharts` 用于绘图 9 | 功能 10 | 迷你登陆微信网页版,获取好友列表性别比例 11 | """ 12 | 13 | import itchat 14 | from pyecharts import Pie 15 | 16 | itchat.auto_login(hotReload=True) #登陆微信 17 | 18 | myFriendList = itchat.get_friends() #获取微信中的好友列表 19 | 20 | sexCounter = {'男' : 0, '女' : 0, '未标注' : 0} 21 | 22 | for friend in myFriendList: 23 | if friend['Sex'] == 1: 24 | sexCounter['男'] += 1 25 | elif friend['Sex'] == 2: 26 | sexCounter['女'] += 1 27 | else: 28 | sexCounter['未标注'] += 1 29 | 30 | pie = Pie('你的微信好友性别比例图',width=1200, height=600, title_pos='center') 31 | attr, value = pie.cast(sexCounter) 32 | '''利用pyecharts的cast方法将字典列表转换成两个列表用于绘图 33 | 例: 34 | tagsList = [{'周一':3},{'周二':2},{'周三':1}] 35 | 用cast方法获得 36 | attr = ['周一','周二','周三'] 37 | value = [3,2,1] 38 | ''' 39 | pie.add( 40 | '', attr, value, 41 | is_label_show = True, 42 | legend_orient = 'vertical', # 图例是否垂直 43 | legend_pos = 'left' 44 | ) 45 | 46 | pie.render('./你的微信好友性别比例图.html') # 绘图渲染 47 | -------------------------------------------------------------------------------- /signUp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | 【例子】微信报名签到小工具 6 | 使用: 7 | 在微信群中,@<签到管理器>报名,即时返回签到信息 8 | 例子: 9 | 小A:@小T 报名 10 | 小T:收到,目前报名人有 11 | 1.小A 12 | """ 13 | 14 | import itchat 15 | from collections import Counter 16 | 17 | @itchat.msg_register(itchat.content.TEXT, isGroupChat=True) 18 | def signUp(msg): 19 | textMsg = msg['Text'] 20 | # 获取信息的文本信息 21 | robotHostName = '@' + myself['NickName'] 22 | rawMessage = textMsg.replace(robotHostName, '').strip() 23 | # 去除掉@<机器人名>之后的文本 24 | groupID = msg['FromUserName'] 25 | # 群ID 26 | if msg.isAt and rawMessage == '报名': 27 | if signCounter[groupID] == 0 : 28 | sendMsg[groupID] = '收到,目前报名人有:' 29 | # 若第一次@,则创建该群下的计数和信息记录 30 | 31 | signCounter[groupID] += 1 32 | signUser = msg['ActualNickName'] 33 | sendMsg[groupID] = sendMsg[groupID] + '\n' + str(signCounter[groupID]) + '.' + signUser 34 | # 将报名计数迭代,且将报名信息更新 35 | # 每一次添加字符串 <迭代次数>.<报名人ID> 36 | 37 | print(sendMsg[groupID]) 38 | # 控制台输出 39 | itchat.send(sendMsg[groupID], groupID) 40 | # 将内容发送到群里 41 | 42 | if __name__ == '__main__': 43 | signCounter = Counter() 44 | sendMsg = {} 45 | 46 | itchat.auto_login(hotReload=True) 47 | myself = itchat.search_friends() 48 | # 获取自身账号信息 49 | itchat.run() -------------------------------------------------------------------------------- /transfer_single.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | 【例】微信转发消息工具,转发指定群个人消息至另外一群 6 | 例如: 7 | --在群聊A中,小T发消息:你好 8 | --在群聊B中有转发消息:及时收到来自群聊【A】,@小T的消息:你好 9 | 使用: 10 | --运行本程序即可,关闭退出即可 11 | 说明: 12 | --目前仅限于接收和转化文本消息,图片、语音、视频、文件暂时未添加功能。 13 | """ 14 | 15 | import itchat 16 | 17 | @itchat.msg_register([itchat.content.TEXT], isGroupChat=True) 18 | def transfer(msg): 19 | print('有群聊消息') 20 | 21 | if msg['ToUserName'] == groupID and msg['FromUserName'] == userID: 22 | ''' 23 | 此处注意: 24 | 如果是转化自己发出的消息到其他群应设置判断条件为 25 | msg['ToUserName'] == groupID and msg['FromUserName'] == userID 26 | 转化发别人消息到其他群则为 27 | msg['ToUserName'] == userID and msg['FromUserName'] == groupID 28 | ''' 29 | print('收到关注消息') 30 | 31 | for toGroup in toGroupList: 32 | toGroupIDList = itchat.search_chatrooms(name=toGroup) 33 | toGroupID = toGroupIDList[0]['UserName'] 34 | itchat.send('及时转发来自群【{}】,@{}的消息:{}'.format(groupName,userName,msg['Content']),toGroupID) 35 | 36 | print('已转发完成') 37 | 38 | def main(userName,groupName,toGroupList): 39 | global groupID 40 | global userID 41 | 42 | itchat.auto_login(hotReload=True) 43 | # 登陆微信 44 | searchedGroupList = itchat.search_chatrooms(name=groupName) 45 | groupID = searchedGroupList[0]['UserName'] 46 | chatRoom = itchat.update_chatroom(groupID, detailedMember=True) 47 | # 搜索指定群聊的id 48 | for member in chatRoom['MemberList']: 49 | if member['NickName'] == userName: 50 | userID = member['UserName'] 51 | # 在指定群聊中搜索指定人员的id 52 | 53 | # print('userID = {}\ngroupID = {}\n'.format(userID,groupID)) 54 | 55 | itchat.run() 56 | # 开始搜索 57 | 58 | if __name__ == '__main__': 59 | '''以下可修改为 60 | ''' 61 | userName = 'Tenkey' 62 | groupName = '新时代文化交流群' 63 | toGroupList = ['啊哈'] 64 | main(userName,groupName,toGroupList) 65 | -------------------------------------------------------------------------------- /wordCloud.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | 6 | 【例子】:对微信好友的个性签名生成词云图 7 | 引入库说明 8 | `itchat` 模拟登陆网页版微信 9 | `jieba` 用于分词 10 | `pyecharts` 用于绘图 11 | `collections` 使用Counter经行计数 12 | 功能 13 | 模拟登陆微信网页版,获取好友列表签名生成词云图 14 | 在本文件目录下生成词云图的 .html 文件 15 | 16 | """ 17 | 18 | import itchat 19 | import jieba.analyse 20 | from pyecharts import WordCloud 21 | from collections import Counter 22 | 23 | itchat.auto_login(hotReload=True) #登陆微信 24 | 25 | myFriendsList = itchat.get_friends() #获取微信中的好友列表 26 | 27 | signatureCounter = Counter() #生成一个Counter对象,后续用于词频的计数 28 | for friend in myFriendsList: 29 | signature = friend['Signature'] 30 | signature = signature.strip().replace('emoji','').replace('class','').replace('span','') #替换好友签名中表情的代码文本 31 | tags = jieba.analyse.extract_tags(signature) #利用jieba分词,统计词频 32 | for tag in tags: 33 | signatureCounter[tag] += 1 34 | tagsList = signatureCounter.most_common(200) #选出分词后词频最高的200个词 35 | 36 | wordCloud = WordCloud('你的微信好友签名云图',width=1200, height=600, title_pos='center') #生成一个词云图对象,用于绘制词云图,在这里设置标题、高度宽度和位置 37 | attr, value = wordCloud.cast(tagsList) 38 | '''利用pyecharts的cast方法将字典列表转换成两个列表用于绘图 39 | 例: 40 | tagsList = [{'周一':3},{'周二':2},{'周三':1}] 41 | 用cast方法获得 42 | attr = ['周一','周二','周三'] 43 | value = [3,2,1] 44 | ''' 45 | wordCloud.add( 46 | '',attr,value, 47 | shape = 'star', 48 | ) 49 | '''设置词云图属性,将分词列列表和词频列表添加进入 50 | 设置词云图形状为'start' 51 | 还有的图形 'cardioid', 'diamond', 'triangle-forward', 'triangle', 'pentagon', 'star' 52 | 53 | ''' 54 | wordCloud.render('./你的微信好友签名云图.html') #渲染,在本程序目录下生成.html文件 --------------------------------------------------------------------------------