Python学习资料整理Python

玩转Python发微信之itchat

2019-06-16  本文已影响80人  惑也

一、说明

#-*- coding: utf-8 -*-
import pandas as pd
import numpy as np
import plotly.offline as py                      # 保存图表,同于plotly.plotly as py,同时增加了离线功能
py.init_notebook_mode(connected=True)            # 离线绘图时,需要额外进行初始化
import plotly.graph_objs as go                   # 创建各类图表
import plotly.figure_factory as ff               # 创建table
from plotly import tools
import matplotlib.pyplot as plt
from pyecharts import options as opts            # 配置echarts
from pyecharts.globals import ThemeType, SymbolType
from pyecharts.charts import Geo, Map, Page
from IPython.display import HTML, display

import itchat    
import jieba                                     # 中文分词   
 
from googletrans import Translator               # 翻译
translate = Translator().translate
from scipy.misc import imread                    # 获取图片,读为np.array的三维数组
from PIL import Image                            # 操作图片
from wordcloud import WordCloud                  # 词云
import os, math

二、安装

pip install itchat

三、登录

1. 登录

itchat.auto_login(hotReload=True, loginCallback=li, exitCallback=lo) 
def li(): print("Log In!")    # 定义登录成功的提示语
def lo(): print("Log Out!")    # 定义退出的提示语

2. 向文件助手发送消息

send_str_1 = "您好吖,猜猜我是谁?\n其实,我是一个机器人儿"
send_str_2 = "您好,机器人自动发消息\n收到了请忽略或任意回复"
for s in [send_str_1, send_str_2]:
    itchat.send(msg=s, toUserName="filehelper")    

3. 退出登录

if 1 == 1: itchat.logout()    # 使用if条件,可以避免输出ItchatReturnValue提示

四、信息获取

friends = itchat.get_friends(update=True)    # 获取通讯录好友列表
contacts = itchat.get_contact(update=True)    # 获取保存到通讯录的微信群
chatrooms = itchat.get_chatrooms(update=True)    # 获取近期活跃的微信群
mps = itchat.get_mps()    # 获取关注的微信公众号

五、统计分析

1. 数据处理

# 获取微信好友信息
key_list = ["UserName", "NickName", "RemarkName", "Sex", "Province", "City", "Signature", "HeadImgUrl"] # 好友指标
df_friend = pd.DataFrame()
for friend in friends:
    tmp = dict()
    for i in friend:
        if i not in key_list:
            continue        
        tmp[i] = friend[i]
    term = pd.DataFrame(tmp, index=[0])
    df_friend = df_friend.append(term, sort=False)
    
df_friend = df_friend.reindex(columns=key_list)

# 性别转化为中文
df_friend['Sex'] = df_friend['Sex'].apply(lambda x: '男' if x == 1 else '女')

# 将英文的省份和城市,翻译成中文,若为空时转化为未知
df_friend["Province"] = df_friend["Province"].apply(lambda x: (x if not x.encode('UTF-8').isalpha() else translate(x, dest='zh-CN').text) if x != '' else '未知')
df_friend["City"] = df_friend["City"].apply(lambda x: (x if not x.encode('UTF-8').isalpha() else translate(x, dest='zh-CN').text) if x != '' else '未知')

2. 概括统计

display(HTML(f"<h3 style='color: green'>微信好友数量:{len(friends)}</h3"))

contacts_group_chat = [ql["NickName"] for ql in contacts]
display(HTML(f"<h3 style='color: green'>保存到通讯录的群聊数量:{len(contacts)},&nbsp;&nbsp;具体如下:</h3"))
for gc in contacts_group_chat: print(gc, end='  ')

chatrooms_group_chat = [ql["NickName"] for ql in chatrooms if ql["NickName"] not in contacts_group_chat]
display(HTML(f"<h3 style='color: green'>近期活跃的群聊数量:{len(chatrooms) - len(contacts)},&nbsp;&nbsp;具体如下:</h3"))
for gc in chatrooms_group_chat: print(gc, end='  ')    # 排除已保存通讯录的群

display(HTML(f"<h3 style='color: green'>关注的微信公众号数量:{len(mps)},&nbsp;&nbsp;具体如下:</h3"))
for ql in mps: print(ql["NickName"], end='  ')

3. 男女比例

# 好友性别统计
friend_sex = df_friend.groupby("Sex")["UserName"].count().to_frame().reset_index()
trace = go.Pie(labels=friend_sex.Sex, values=friend_sex.UserName, hole=.4)
layout = dict(width=850, height=450)
fig = dict(data=[trace], layout=layout)
py.iplot(fig)

4. 地域分布

# 好友地域分布
friend_area = df_friend.groupby("Province")["UserName"].count().to_frame().reset_index().sort_values(by="UserName", ascending=False)
trace = go.Bar(x=friend_area.Province, y=friend_area.UserName)
layout = dict(width=900, height=450, xaxis = dict(tickangle = -45))
fig = dict(data=[trace], layout=layout)
py.iplot(fig)

5. 地图分布

# 好友地图分布
china_province = pd.read_excel('province.xlsx')
china_province["Province"] = china_province.province.apply(lambda x: x[0:3] if len(x) in (4, 6) else x[0:2])
friend_area = friend_area[friend_area.Province.isin(china_province.Province)]    # 排除省份为空或国外的地区
area = (Map(opts.InitOpts(width="900px", height="500px", theme=ThemeType.PURPLE_PASSION))
       .add("", [list(z) for z in zip(list(friend_area.Province), list(friend_area.UserName))], maptype="china")
       .set_global_opts(visualmap_opts=opts.VisualMapOpts(max_=int(np.max(friend_area.UserName)), range_text=["多", "少"], range_color=['#FFFF00', '#D6292B']))
       .set_series_opts(label_opts=opts.LabelOpts(is_show=True)))
area.render_notebook()

6. 签名词云

# 好友签名词云
background_image = imread("picture.jpeg")    # 词云背景图,自选,本文选心形
sign_str = ''.join(df_friend.Signature.tolist())    # 签名转化为list

# 仅选取汉字、大小写英文字母,其它的一概忽略
jb_str = ''
for s in sign_str:
    if s.isspace() or (s >= u'\u4e00' and s <= u'\u9fa5') or (s >= u'\u0041' and s <= u'\u005a') or (s >= u'\u0061' and s <= u'\u007a'):
        jb_str += s

# 使用结巴分词,对签名文字进行分词,分词后排除掉单字,因为单字词云无意义     
cut_str = ' '.join([jb for jb in jieba.cut(jb_str) if len(jb) > 1])

# 使用wordcloud包制作词云,可能需要单独安装汉字字体
wordcloud = WordCloud(font_path="/System/Library/Fonts/STHeiti Medium.ttc", scale=4, background_color="white", mask=background_image).generate(cut_str)
fig = plt.gcf()
fig.set_size_inches(18, 12)
plt.imshow(wordcloud, interpolation="lanczos")
plt.axis("off")
plt.show()

7. 头像拼图

# 创建文件夹user_image,存储所有好友头像照片
try:
    os.mkdir("user_image")
except FileExistsError:
    pass

# 下载好友头像,并存储
image_dir = "./user_image/"
for k, friend in enumerate(friends):
    image_name = str(k)+'.jpg'
    user_name = friend["UserName"]
    img = itchat.get_head_img(userName=user_name)
    with open(image_dir + image_name, 'wb') as file:
        file.write(img)

# 根据好友数量,设计头像拼图的最佳行列数
phone_width = 200
phone_height = 200
pic_list = [path for path in os.listdir(image_dir) if path.endswith(".jpg")]    # 头像照片的文件名列表
pic_num = len(pic_list)
array = int(math.sqrt(pic_num))
if array != math.sqrt(pic_num):
    if abs(array * array - pic_num) > abs((array + 1) * (array + 1) - pic_num):
        array = array + 1
    tem = dict()
    for temp in zip(range(1, array + 1)[::-1], range(array + 1, array * 2 + 1)):
        term = abs(temp[0] * temp[1] - pic_num)
        if term in tem:
            continue
        else:
            tem[term] = temp
    row_col = tem[min(tem)]
else:
    row_col = (array, array) 
row_num = row_col[0]
col_num = row_col[1]

# 创建底图,宽为:列数*200px,高为:行数*200px
to_image = Image.new("RGBA", (phone_width * col_num, phone_height * row_num))

# 循环粘贴每一个头像照片
n = 0
for i in range(0, row_num):
    for j in range(0, col_num):
        if n == pic_num:
            break
        image_any = Image.open(image_dir + pic_list[n])    # 读取头像照片
        image_any_size = image_any.resize((phone_width, phone_height))    # 设置照片大小(200px*200px)
        loc = (j * phone_width, i * phone_height)    # 计算照片粘贴的位置
        to_image.paste(image_any_size, loc)    # 粘贴照片
        n += 1
        
# 展示好友头像拼图
fig = plt.gcf()
fig.set_size_inches(16, 9)
plt.imshow(to_image, interpolation="lanczos")
plt.axis("off")
plt.show()

六、发送消息

if 1==1: itchat.send(msg="Python_data_analysis", toUserName="filehelper")    # 发送文字
if True: itchat.send(msg="@fil@%s" % "./Python.txt", toUserName="filehelper")    # 发送文件
if True: itchat.send(msg="@img@%s" % "./picture.jpeg", toUserName="filehelper")    # 发送图片
if True: itchat.send(msg="@vid@%s" % "./Tableau_introduction.mp4", toUserName="filehelper")    # 发送视频

七、自动回复

def from_turing_reply(msg):
    """从图灵机器人获取回复内容"""

    api_url = 'http://www.tuling123.com/openapi/api'
    data = {
        "key": "64496a7591a3450682188885461fc328",
        "info": msg,
        "user_id": "Robot"
    }
    try:
        r = requests.post(api_url, data=data).json()
        return r.get("text")
    except:
        return ''

@itchat.msg_register(itchat.content.TEXT)
def text_reply(msg):
    """自动文本回复"""
    
    default_reply = "我陪主人去月球了,明天再陪你聊!"
    if msg["FromUserName"] in ["@07c0724e5bb70a6e99651277c16daa66"]:  # 指定好友
        reply = from_turing_reply(msg["Text"])
        if "当天请求次数已用完" in reply:
            reply = default_reply
        return reply or default_reply

itchat.run()
上一篇 下一篇

猜你喜欢

热点阅读