update python_wechat.py

master
xianhu 2017-06-27 10:39:25 +08:00
parent e9c6abb727
commit f21f3d687f
1 changed files with 222 additions and 105 deletions

View File

@ -17,9 +17,6 @@ from itchat.content import *
# 初始化 # 初始化
my = itchat.new_instance() my = itchat.new_instance()
my.auto_login(hotReload=False, enableCmdQR=-2) my.auto_login(hotReload=False, enableCmdQR=-2)
my.global_keys = ["创业", "算法", "人工智能", "机器学习"]
my.to_user_name = "filehelper"
# my还包括的以下属性注意用点.查看: # my还包括的以下属性注意用点.查看:
# (1) alive 是否还活着isLogging 是否已登陆 # (1) alive 是否还活着isLogging 是否已登陆
# (2) loginInfo 登陆信息其中的User属性为自己的信息User字典类包括UserName, NickName, RemarkName, Sex(1 or 2), Signature, Province, City等 # (2) loginInfo 登陆信息其中的User属性为自己的信息User字典类包括UserName, NickName, RemarkName, Sex(1 or 2), Signature, Province, City等
@ -27,58 +24,157 @@ my.to_user_name = "filehelper"
# (4) chatroomList 群聊列表每一项为一个Chatroom字典类包括UserName, NickName, RemarkName, MemberCount, MemberList, Self等 # (4) chatroomList 群聊列表每一项为一个Chatroom字典类包括UserName, NickName, RemarkName, MemberCount, MemberList, Self等
# (5) mpList 订阅号列表每一项为一个MassivePlatform字典类包括UserName, NickName等 # (5) mpList 订阅号列表每一项为一个MassivePlatform字典类包括UserName, NickName等
# 获取并更新通讯录: {UserName: UserInstance} my.global_keys = ["创业", "算法", "人工智能", "机器学习"]
my.friends = {user["UserName"]: user for user in my.get_friends(update=True)} my.to_user_name = "filehelper" # 消息接受者
my.update_time = time.time() # 信息更新时间
# 消息存储队列 my.msg_store = {} # 消息存储队列
my.msg_store = {} my.friends = {} # 好友字典列表
my.groups = {} # 群聊字典列表
# 消息提取函数 def update_my_infos():
def get_msg_list(msg):
""" """
提取消息内容消息来源分类 更新信息
"""
# 获取并更新通讯录: {UserName: UserInstance}
my.friends = {user["UserName"]: user for user in my.get_friends(update=True)}
# 获取并更新群列表: {UserName: UserInstance}
my.groups = {group["UserName"]: group for group in my.get_chatrooms(update=True)}
return
update_my_infos()
class Message(object):
"""
消息类
"""
def __init__(self, msg):
"""
构造函数提取消息内容
消息来源分类
1来自好友的消息 1来自好友的消息
2来自群的消息 2来自群的消息
3来自文件传输助手的消息
提取消息内容消息类型分类 提取消息内容消息类型分类
1文字2图片3语音4视频5地址6名片7提醒8分享9附件 1文字2图片3语音4视频5地址6名片7提醒8分享9附件
""" """
# 更新信息,十分钟更新一次
# logging.warning("message: %s", msg) # logging.warning("message: %s", msg)
msg_id = msg["MsgId"] # 消息ID if time.time() - my.update_time > 600:
from_user_name = msg["FromUserName"] # 消息发送者ID如果为群消息则为群ID update_my_infos()
to_user_name = msg["ToUserName"] # 消息接受者ID如果为群消息则为群ID my.update_time = time.time()
msg_type = msg["MsgType"] # 消息类型 self.msg_id = msg["MsgId"] # 消息ID
msg_content = msg["Content"] # 消息内容 self.from_user_name = msg["FromUserName"] # 消息发送者ID如果为群消息则为群ID
msg_time = msg["CreateTime"] # 消息发送时间
msg_file = msg["FileName"] # 消息中所带文件的名称 self.msg_type = msg["MsgType"] # 消息类型这里参考下边的we_type
msg_file_length = msg["FileSize"] # 消息中所带文件的大小 self.msg_content = msg["Content"] # 消息内容这里参考下边的we_text
msg_voice_length = msg["VoiceLength"] # 消息中所带语音的长度(毫秒) self.msg_time = msg["CreateTime"] # 消息发送时间,时间戳格式
msg_play_length = msg["PlayLength"] # 消息中所带视频的长度(秒)
msg_url = msg["Url"] # 消息中所带链接的地址
wind_name = msg["User"]["RemarkName"] if msg["User"].get("RemarkName") else ( self.msg_file = msg["FileName"] # 消息中所带文件的名称
msg["User"]["NickName"] if msg["User"].get("NickName") else to_user_name self.msg_file_length = msg["FileSize"] # 消息中所带文件的大小,字符串类型
) # 窗口名称:群名或好友名 self.msg_voice_length = msg["VoiceLength"] # 消息中所带语音的长度(毫秒)
self.msg_play_length = msg["PlayLength"] # 消息中所带视频的长度(秒)
self.msg_url = msg["Url"] # 消息中所带链接的地址
msg_user_name = from_user_name # 消息发送者的ID self.user_user_name = msg["User"].get("UserName", "") # 消息发送者ID如果为群消息则为群ID
msg_nick_name = wind_name # 消息发送者的昵称 self.user_nick_name = msg["User"].get("NickName", "") # 消息发送者昵称,如果为群消息,则为群名
if from_user_name.startswith("@@") or to_user_name.startswith("@@"): self.user_remark_name = msg["User"].get("RemarkName", "") # 消息发送者备注名称,如果为群消息,则为群备注名称
msg_user_name = msg["ActualUserName"] self.wind_name = self.user_remark_name if self.user_remark_name else (
msg_nick_name = msg["ActualNickName"] if (msg_user_name not in my.friends) or (not my.friends[msg_user_name]["RemarkName"]) else my.friends[msg_user_name]["RemarkName"] self.user_nick_name if self.user_nick_name else (
my.friends[self.user_user_name]["NickName"] if self.user_user_name in my.friends else (
my.groups[self.user_user_name]["NickName"] if self.user_user_name in my.groups else "未知窗口"
)
)
)
is_at = msg.get("IsAt", None) # 是否在群内被@ self.actual_user_name = msg.get("ActualUserName", "") # 群消息中消息发送者的ID
we_type = msg["Type"] # 消息类型 self.actual_nick_name = msg.get("ActualNickName", "") # 群消息中,消息发送者的群昵称
we_text = msg["Text"] # 消息内容 self.actual_remark_name = self.actual_nick_name \
if (self.actual_user_name not in my.friends) or (not my.friends[self.actual_user_name]["RemarkName"]) \
else my.friends[self.actual_user_name]["RemarkName"]
logging.warning("show: msg_nick_name=%s, wind_name=%s, we_type=%s, we_text=%s", msg_nick_name, wind_name, we_type, we_text) self.is_at = msg.get("IsAt", None) # 是否在群内被@
return msg_id, from_user_name, to_user_name, msg_type, msg_content, msg_time, msg_file, msg_file_length, msg_voice_length, msg_play_length, msg_url, \ self.we_type = msg["Type"] # 消息类型
wind_name, msg_user_name, msg_nick_name, is_at, we_type, we_text self.we_text = msg["Text"] # 消息内容
logging.warning("show: wind_name=%s, actual_send_name=%s, we_type=%s, we_text=%s", self.wind_name, self.actual_remark_name, self.we_type, self.we_text)
return
def process_message_group(msg):
"""
处理群消息
"""
# 消息过滤, 只监测文字、图片、语音、名片、注解、分享等
if msg.we_type not in ["Text", "Picture", "Recording", "Card", "Note", "Sharing"]:
logging.warning("process_message_group: message type isn't included, ignored")
return
# ==== 处理红包消息 ====
if msg.we_type == "Note" and msg.we_text.find("收到红包,请在手机上查看") >= 0:
my.send("%s】中有人发红包啦,快抢!" % msg.wind_name, toUserName=my.to_user_name)
# ==== 处理关键词消息 ====
for key in my.global_keys:
if msg.we_type == "Text" and msg.we_text.find(key) >= 0:
my.send("%s】中【%s】提及了关键字:%s" % (msg.wind_name, msg.actual_remark_name, key), toUserName=my.to_user_name)
my.send(msg.we_text, toUserName=my.to_user_name)
break
# ==== 群内是否被@ ====
if msg.we_type == "Text" and msg.is_at:
my.send("%s】中【%s】@了你" % (msg.wind_name, msg.actual_remark_name), toUserName=my.to_user_name)
my.send(msg.we_text, toUserName=my.to_user_name)
return
def process_message_revoke(msg):
"""
处理撤回消息
"""
# 消息过滤, 只监测文字、图片、语音、名片、注解、分享等
if msg.we_type not in ["Text", "Picture", "Recording", "Card", "Note", "Sharing"]:
logging.warning("process_message_revoke: message type isn't included, ignored")
return
# 消息存储,删除过期消息
my.msg_store[msg.msg_id] = msg
for _id in [_id for _id in my.msg_store if time.time() - my.msg_store[_id].msg_time > 120]:
my.msg_store.pop(_id)
# 保存消息中的内容(图片、语音等)
if msg.we_type in ["Picture", "Recording"]:
try:
msg.we_text(".Cache/" + msg.msg_file)
logging.warning("process_message_revoke: download %s to .Cache/", msg.msg_file)
except Exception as excep:
logging.error("process_message_revoke: download %s to .Cache/ error: %s", msg.msg_file, excep)
# ==== 撤回消息处理(必须为最后一步) ====
if msg.we_type == "Note" and msg.we_text.find("撤回了一条消息") >= 0:
old_msg = my.msg_store.get(msg.msg_content[msg.msg_content.find("<msgid>")+7: msg.msg_content.find("</msgid>")])
if not old_msg:
logging.warning("process_message_revoke: no message id in my.msg_store")
return
if old_msg.from_user_name.startswith("@@"):
my.send("%s】中【%s】撤回了自己发送的消息:\nType: %s\nTime: %s\n%s" %
(old_msg.wind_name, old_msg.actual_remark_name, old_msg.we_type, old_msg.msg_time, old_msg.msg_file), toUserName=my.to_user_name)
else:
my.send("%s】撤回了自己发送的消息:\nType: %s\nTime: %s\n%s" %
(old_msg.wind_name, old_msg.we_type, old_msg.msg_time, old_msg.msg_file), toUserName=my.to_user_name)
if old_msg.we_type in ["Text", "Card"]:
my.send(str(old_msg.we_text), toUserName=my.to_user_name)
elif old_msg.we_type == "Sharing":
my.send(old_msg.we_text + "\n" + old_msg.msg_url, toUserName=my.to_user_name)
elif old_msg.we_type == "Picture":
my.send_image(".Cache/" + old_msg.msg_file, toUserName=my.to_user_name)
elif old_msg.we_type == "Recording":
my.send_file(".Cache/" + old_msg.msg_file, toUserName=my.to_user_name)
return
# 消息注册,主要处理群消息
@my.msg_register([TEXT, PICTURE, RECORDING, VIDEO, MAP, CARD, NOTE, SHARING, ATTACHMENT], isFriendChat=True, isGroupChat=True) @my.msg_register([TEXT, PICTURE, RECORDING, VIDEO, MAP, CARD, NOTE, SHARING, ATTACHMENT], isFriendChat=True, isGroupChat=True)
def text_reply(msg): def text_reply(msg):
""" """
@ -89,64 +185,14 @@ def text_reply(msg):
return return
# 消息提取 # 消息提取
msg_list = get_msg_list(msg) msg = Message(msg)
msg_id, from_user_name, to_user_name, msg_type, msg_content, msg_time, msg_file, msg_file_length, msg_voice_length, msg_play_length, msg_url, \
wind_name, msg_user_name, msg_nick_name, is_at, we_type, we_text = msg_list
# 消息过滤, 只监测文字、图片、语音、名片、注解、分享等 # 处理群消息
if we_type not in ["Text", "Picture", "Recording", "Card", "Note", "Sharing"]: if msg.from_user_name.startswith("@@"):
logging.warning("message type isn't included, ignored") process_message_group(msg)
return
# 消息存储,删除过期消息
my.msg_store[msg_id] = msg_list
for _id in [_id for _id in my.msg_store if time.time() - my.msg_store[_id][5] > 120]:
my.msg_store.pop(_id)
# 保存消息中的内容(图片、语音等),不保存动态图片
if (we_type in ["Picture", "Recording"]) and (not msg_file.endswith(".gif")):
try:
we_text(".Cache/" + msg_file)
logging.warning("downloading %s to .Cache/", msg_file)
except Exception as excep:
logging.error("downloading %s to .Cache/ error: %s", msg_file, excep)
# ==== 处理群消息 ====
if from_user_name.startswith("@@"):
# ==== 处理红包消息 ====
if we_type == "Note" and we_text.find("收到红包,请在手机上查看") >= 0:
my.send("%s】中有人发红包啦,快抢!" % wind_name, toUserName=my.to_user_name)
# ==== 处理关键词消息 ====
for key in my.global_keys:
if we_type == "Text" and we_text.find(key) >= 0:
my.send("%s】中【%s】提及了关键字:%s" % (wind_name, msg_nick_name, key), toUserName=my.to_user_name)
my.send(we_text, toUserName=my.to_user_name)
break
# ==== 群内是否被@ ====
if we_type == "Text" and is_at:
my.send("%s】中【%s】@了你" % (wind_name, msg_nick_name), toUserName=my.to_user_name)
my.send(we_text, toUserName=my.to_user_name)
# ==== 撤回消息处理(必须为最后一步) ====
if we_type == "Note" and we_text.find("撤回了一条消息") >= 0:
msg_list = my.msg_store.get(msg_content[msg_content.find("<msgid>")+7: msg_content.find("</msgid>")])
if not msg_list:
logging.warning("not message id in my.msg_store")
return
msg_id, from_user_name, to_user_name, msg_type, msg_content, msg_time, msg_file, msg_file_length, msg_voice_length, msg_play_length, msg_url, \
wind_name, msg_user_name, msg_nick_name, is_at, we_type, we_text = msg_list
my.send("%s】中【%s】撤回了自己发送的消息:\nType: %s\nTime: %s\n%s" % (wind_name, msg_nick_name, we_type, msg_time, msg_file), toUserName=my.to_user_name)
if we_type in ["Text", "Card"]:
my.send(str(we_text), toUserName=my.to_user_name)
elif we_type == "Sharing":
my.send(we_text + "\n" + msg_url, toUserName=my.to_user_name)
elif we_type == "Recording":
my.send_file(".Cache/" + msg_file, toUserName=my.to_user_name)
elif we_type == "Picture" and (not msg_file.endswith(".gif")):
my.send_image(".Cache/" + msg_file, toUserName=my.to_user_name)
# 处理撤回消息
process_message_revoke(msg)
return return
@ -332,4 +378,75 @@ my.run(debug=False)
'Type': 'Text', 'Type': 'Text',
'Text': '就是那个,那个协议我们手上有吗' 'Text': '就是那个,那个协议我们手上有吗'
} }
警示消息好友类
{
'MsgId': '1529895072288746571',
'FromUserName': '@4076708be2e09ef83f249f168553d0dd55b4f734aee7d276e92ddbe98625476a',
'ToUserName': '@f97583d8ffbaee6189854116897c677f',
'MsgType': 10000,
'Content': '你已添加了呼啸而过的小青春,现在可以开始聊天了。',
'Status': 4,
'ImgStatus': 1,
'CreateTime': 1498533407,
'VoiceLength': 0,
'PlayLength': 0,
'FileName': '',
'FileSize': '',
'MediaId': '',
'Url': '',
'AppMsgType': 0,
'StatusNotifyCode': 0,
'StatusNotifyUserName': '',
'HasProductId': 0,
'Ticket': '',
'ImgHeight': 0,
'ImgWidth': 0,
'SubMsgType': 0,
'NewMsgId': 1529895072288746571,
'OriContent': '',
'User': <User: {
'userName': '@4076708be2e09ef83f249f168553d0dd55b4f734aee7d276e92ddbe98625476a',
'MemberList': <ContactList: []>
}>,
'Type': 'Note',
'Text': '你已添加了呼啸而过的小青春,现在可以开始聊天了。'
}
警示消息群类
{
'MsgId': '1049646282086057263',
'FromUserName': '@@300f57b68ca7ef593ae3221eef7dba5377466c86122aaa15a8ffc1031310e210',
'ToUserName': '@006f63e8086ab07fcbe3771dc824c4a6',
'MsgType': 10000,
'Content': '你邀请"大姐"加入了群聊',
'Status': 3,
'ImgStatus': 1,
'CreateTime': 1498533901,
'VoiceLength': 0,
'PlayLength': 0,
'FileName': '',
'FileSize': '',
'MediaId': '',
'Url': '',
'AppMsgType': 0,
'StatusNotifyCode': 0,
'StatusNotifyUserName': '',
'HasProductId': 0,
'Ticket': '',
'ImgHeight': 0,
'ImgWidth': 0,
'SubMsgType': 0,
'NewMsgId': 1049646282086057263,
'OriContent': '',
'ActualUserName': '@006f63e8086ab07fcbe3771dc824c4a6',
'ActualNickName': '某某某',
'IsAt': False,
'User': <Chatroom: {
'UserName': '@@300f57b68ca7ef593ae3221eef7dba5377466c86122aaa15a8ffc1031310e210',
'MemberList': <ContactList: []>
}>,
'Type': 'Note',
'Text': '你邀请"大姐"加入了群聊'
}
""" """