Skip to content

Commit f21f3d6

Browse files
committed
update python_wechat.py
1 parent e9c6abb commit f21f3d6

File tree

1 file changed

+208
-91
lines changed

1 file changed

+208
-91
lines changed

python_wechat.py

Lines changed: 208 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -17,136 +17,182 @@
1717
# 初始化
1818
my = itchat.new_instance()
1919
my.auto_login(hotReload=False, enableCmdQR=-2)
20-
my.global_keys = ["创业", "算法", "人工智能", "机器学习"]
21-
my.to_user_name = "filehelper"
22-
2320
# my还包括的以下属性,注意用点.查看:
2421
# (1) alive 是否还活着,isLogging 是否已登陆
2522
# (2) loginInfo 登陆信息,其中的User属性为自己的信息User字典类,包括UserName, NickName, RemarkName, Sex(1 or 2), Signature, Province, City等
2623
# (3) memberList 通讯录列表,每一项为一个User字典类,包括UserName, NickName, RemarkName, Sex(1 or 2), Signature, Province, City等
2724
# (4) chatroomList 群聊列表,每一项为一个Chatroom字典类,包括UserName, NickName, RemarkName, MemberCount, MemberList, Self等
2825
# (5) mpList 订阅号列表,每一项为一个MassivePlatform字典类,包括UserName, NickName等
2926

30-
# 获取并更新通讯录: {UserName: UserInstance}
31-
my.friends = {user["UserName"]: user for user in my.get_friends(update=True)}
27+
my.global_keys = ["创业", "算法", "人工智能", "机器学习"]
28+
my.to_user_name = "filehelper" # 消息接受者
29+
my.update_time = time.time() # 信息更新时间
30+
my.msg_store = {} # 消息存储队列
31+
my.friends = {} # 好友字典列表
32+
my.groups = {} # 群聊字典列表
3233

33-
# 消息存储队列
34-
my.msg_store = {}
34+
35+
def update_my_infos():
36+
"""
37+
更新信息
38+
"""
39+
# 获取并更新通讯录: {UserName: UserInstance}
40+
my.friends = {user["UserName"]: user for user in my.get_friends(update=True)}
41+
# 获取并更新群列表: {UserName: UserInstance}
42+
my.groups = {group["UserName"]: group for group in my.get_chatrooms(update=True)}
43+
return
44+
update_my_infos()
3545

3646

37-
# 消息提取函数
38-
def get_msg_list(msg):
47+
class Message(object):
3948
"""
40-
提取消息内容,消息来源分类:
41-
(1)来自好友的消息
42-
(2)来自群的消息
43-
(3)来自文件传输助手的消息
44-
提取消息内容,消息类型分类:
45-
(1)文字(2)图片(3)语音(4)视频(5)地址(6)名片(7)提醒(8)分享(9)附件
49+
消息类
4650
"""
47-
# logging.warning("message: %s", msg)
48-
msg_id = msg["MsgId"] # 消息ID
49-
from_user_name = msg["FromUserName"] # 消息发送者ID,如果为群消息,则为群ID
50-
to_user_name = msg["ToUserName"] # 消息接受者ID,如果为群消息,则为群ID
51+
def __init__(self, msg):
52+
"""
53+
构造函数:提取消息内容
54+
消息来源分类:
55+
(1)来自好友的消息
56+
(2)来自群的消息
57+
提取消息内容,消息类型分类:
58+
(1)文字(2)图片(3)语音(4)视频(5)地址(6)名片(7)提醒(8)分享(9)附件
59+
"""
60+
# 更新信息,十分钟更新一次
61+
# logging.warning("message: %s", msg)
62+
if time.time() - my.update_time > 600:
63+
update_my_infos()
64+
my.update_time = time.time()
5165

52-
msg_type = msg["MsgType"] # 消息类型
53-
msg_content = msg["Content"] # 消息内容
54-
msg_time = msg["CreateTime"] # 消息发送时间
66+
self.msg_id = msg["MsgId"] # 消息ID
67+
self.from_user_name = msg["FromUserName"] # 消息发送者ID,如果为群消息,则为群ID
5568

56-
msg_file = msg["FileName"] # 消息中所带文件的名称
57-
msg_file_length = msg["FileSize"] # 消息中所带文件的大小
58-
msg_voice_length = msg["VoiceLength"] # 消息中所带语音的长度(毫秒)
59-
msg_play_length = msg["PlayLength"] # 消息中所带视频的长度(秒)
60-
msg_url = msg["Url"] # 消息中所带链接的地址
69+
self.msg_type = msg["MsgType"] # 消息类型,这里参考下边的we_type
70+
self.msg_content = msg["Content"] # 消息内容,这里参考下边的we_text
71+
self.msg_time = msg["CreateTime"] # 消息发送时间,时间戳格式
6172

62-
wind_name = msg["User"]["RemarkName"] if msg["User"].get("RemarkName") else (
63-
msg["User"]["NickName"] if msg["User"].get("NickName") else to_user_name
64-
) # 窗口名称:群名或好友名
73+
self.msg_file = msg["FileName"] # 消息中所带文件的名称
74+
self.msg_file_length = msg["FileSize"] # 消息中所带文件的大小,字符串类型
75+
self.msg_voice_length = msg["VoiceLength"] # 消息中所带语音的长度(毫秒)
76+
self.msg_play_length = msg["PlayLength"] # 消息中所带视频的长度(秒)
77+
self.msg_url = msg["Url"] # 消息中所带链接的地址
6578

66-
msg_user_name = from_user_name # 消息发送者的ID
67-
msg_nick_name = wind_name # 消息发送者的昵称
68-
if from_user_name.startswith("@@") or to_user_name.startswith("@@"):
69-
msg_user_name = msg["ActualUserName"]
70-
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"]
79+
self.user_user_name = msg["User"].get("UserName", "") # 消息发送者ID,如果为群消息,则为群ID
80+
self.user_nick_name = msg["User"].get("NickName", "") # 消息发送者昵称,如果为群消息,则为群名
81+
self.user_remark_name = msg["User"].get("RemarkName", "") # 消息发送者备注名称,如果为群消息,则为群备注名称
82+
self.wind_name = self.user_remark_name if self.user_remark_name else (
83+
self.user_nick_name if self.user_nick_name else (
84+
my.friends[self.user_user_name]["NickName"] if self.user_user_name in my.friends else (
85+
my.groups[self.user_user_name]["NickName"] if self.user_user_name in my.groups else "未知窗口"
86+
)
87+
)
88+
)
7189

72-
is_at = msg.get("IsAt", None) # 是否在群内被@
73-
we_type = msg["Type"] # 消息类型
74-
we_text = msg["Text"] # 消息内容
90+
self.actual_user_name = msg.get("ActualUserName", "") # 群消息中,消息发送者的ID
91+
self.actual_nick_name = msg.get("ActualNickName", "") # 群消息中,消息发送者的群昵称
92+
self.actual_remark_name = self.actual_nick_name \
93+
if (self.actual_user_name not in my.friends) or (not my.friends[self.actual_user_name]["RemarkName"]) \
94+
else my.friends[self.actual_user_name]["RemarkName"]
7595

76-
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)
77-
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, \
78-
wind_name, msg_user_name, msg_nick_name, is_at, we_type, we_text
96+
self.is_at = msg.get("IsAt", None) # 是否在群内被@
97+
self.we_type = msg["Type"] # 消息类型
98+
self.we_text = msg["Text"] # 消息内容
7999

100+
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)
101+
return
80102

81-
# 消息注册,主要处理群消息
82-
@my.msg_register([TEXT, PICTURE, RECORDING, VIDEO, MAP, CARD, NOTE, SHARING, ATTACHMENT], isFriendChat=True, isGroupChat=True)
83-
def text_reply(msg):
103+
104+
def process_message_group(msg):
84105
"""
85-
消息自动接收, 接受全部的消息(自己发送的消息除外)
106+
处理群消息
86107
"""
87-
# 跳过来自自己的消息
88-
if msg["FromUserName"] == my.loginInfo["User"]["UserName"]:
108+
# 消息过滤, 只监测文字、图片、语音、名片、注解、分享等
109+
if msg.we_type not in ["Text", "Picture", "Recording", "Card", "Note", "Sharing"]:
110+
logging.warning("process_message_group: message type isn't included, ignored")
89111
return
90112

91-
# 消息提取
92-
msg_list = get_msg_list(msg)
93-
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, \
94-
wind_name, msg_user_name, msg_nick_name, is_at, we_type, we_text = msg_list
113+
# ==== 处理红包消息 ====
114+
if msg.we_type == "Note" and msg.we_text.find("收到红包,请在手机上查看") >= 0:
115+
my.send("【%s】中有人发红包啦,快抢!" % msg.wind_name, toUserName=my.to_user_name)
116+
117+
# ==== 处理关键词消息 ====
118+
for key in my.global_keys:
119+
if msg.we_type == "Text" and msg.we_text.find(key) >= 0:
120+
my.send("【%s】中【%s】提及了关键字:%s" % (msg.wind_name, msg.actual_remark_name, key), toUserName=my.to_user_name)
121+
my.send(msg.we_text, toUserName=my.to_user_name)
122+
break
123+
124+
# ==== 群内是否被@ ====
125+
if msg.we_type == "Text" and msg.is_at:
126+
my.send("【%s】中【%s】@了你" % (msg.wind_name, msg.actual_remark_name), toUserName=my.to_user_name)
127+
my.send(msg.we_text, toUserName=my.to_user_name)
128+
return
129+
95130

131+
def process_message_revoke(msg):
132+
"""
133+
处理撤回消息
134+
"""
96135
# 消息过滤, 只监测文字、图片、语音、名片、注解、分享等
97-
if we_type not in ["Text", "Picture", "Recording", "Card", "Note", "Sharing"]:
98-
logging.warning("message type isn't included, ignored")
136+
if msg.we_type not in ["Text", "Picture", "Recording", "Card", "Note", "Sharing"]:
137+
logging.warning("process_message_revoke: message type isn't included, ignored")
99138
return
100139

101140
# 消息存储,删除过期消息
102-
my.msg_store[msg_id] = msg_list
103-
for _id in [_id for _id in my.msg_store if time.time() - my.msg_store[_id][5] > 120]:
141+
my.msg_store[msg.msg_id] = msg
142+
for _id in [_id for _id in my.msg_store if time.time() - my.msg_store[_id].msg_time > 120]:
104143
my.msg_store.pop(_id)
105144

106-
# 保存消息中的内容(图片、语音等),不保存动态图片
107-
if (we_type in ["Picture", "Recording"]) and (not msg_file.endswith(".gif")):
145+
# 保存消息中的内容(图片、语音等)
146+
if msg.we_type in ["Picture", "Recording"]:
108147
try:
109-
we_text(".Cache/" + msg_file)
110-
logging.warning("downloading %s to .Cache/", msg_file)
148+
msg.we_text(".Cache/" + msg.msg_file)
149+
logging.warning("process_message_revoke: download %s to .Cache/", msg.msg_file)
111150
except Exception as excep:
112-
logging.error("downloading %s to .Cache/ error: %s", msg_file, excep)
113-
114-
# ==== 处理群消息 ====
115-
if from_user_name.startswith("@@"):
116-
# ==== 处理红包消息 ====
117-
if we_type == "Note" and we_text.find("收到红包,请在手机上查看") >= 0:
118-
my.send("【%s】中有人发红包啦,快抢!" % wind_name, toUserName=my.to_user_name)
119-
# ==== 处理关键词消息 ====
120-
for key in my.global_keys:
121-
if we_type == "Text" and we_text.find(key) >= 0:
122-
my.send("【%s】中【%s】提及了关键字:%s" % (wind_name, msg_nick_name, key), toUserName=my.to_user_name)
123-
my.send(we_text, toUserName=my.to_user_name)
124-
break
125-
# ==== 群内是否被@ ====
126-
if we_type == "Text" and is_at:
127-
my.send("【%s】中【%s】@了你" % (wind_name, msg_nick_name), toUserName=my.to_user_name)
128-
my.send(we_text, toUserName=my.to_user_name)
151+
logging.error("process_message_revoke: download %s to .Cache/ error: %s", msg.msg_file, excep)
129152

130153
# ==== 撤回消息处理(必须为最后一步) ====
131-
if we_type == "Note" and we_text.find("撤回了一条消息") >= 0:
132-
msg_list = my.msg_store.get(msg_content[msg_content.find("<msgid>")+7: msg_content.find("</msgid>")])
133-
if not msg_list:
134-
logging.warning("not message id in my.msg_store")
154+
if msg.we_type == "Note" and msg.we_text.find("撤回了一条消息") >= 0:
155+
old_msg = my.msg_store.get(msg.msg_content[msg.msg_content.find("<msgid>")+7: msg.msg_content.find("</msgid>")])
156+
if not old_msg:
157+
logging.warning("process_message_revoke: no message id in my.msg_store")
135158
return
136159

137-
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, \
138-
wind_name, msg_user_name, msg_nick_name, is_at, we_type, we_text = msg_list
139-
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)
160+
if old_msg.from_user_name.startswith("@@"):
161+
my.send("【%s】中【%s】撤回了自己发送的消息:\nType: %s\nTime: %s\n%s" %
162+
(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)
163+
else:
164+
my.send("【%s】撤回了自己发送的消息:\nType: %s\nTime: %s\n%s" %
165+
(old_msg.wind_name, old_msg.we_type, old_msg.msg_time, old_msg.msg_file), toUserName=my.to_user_name)
166+
167+
if old_msg.we_type in ["Text", "Card"]:
168+
my.send(str(old_msg.we_text), toUserName=my.to_user_name)
169+
elif old_msg.we_type == "Sharing":
170+
my.send(old_msg.we_text + "\n" + old_msg.msg_url, toUserName=my.to_user_name)
171+
elif old_msg.we_type == "Picture":
172+
my.send_image(".Cache/" + old_msg.msg_file, toUserName=my.to_user_name)
173+
elif old_msg.we_type == "Recording":
174+
my.send_file(".Cache/" + old_msg.msg_file, toUserName=my.to_user_name)
175+
return
176+
177+
178+
@my.msg_register([TEXT, PICTURE, RECORDING, VIDEO, MAP, CARD, NOTE, SHARING, ATTACHMENT], isFriendChat=True, isGroupChat=True)
179+
def text_reply(msg):
180+
"""
181+
消息自动接收, 接受全部的消息(自己发送的消息除外)
182+
"""
183+
# 跳过来自自己的消息
184+
if msg["FromUserName"] == my.loginInfo["User"]["UserName"]:
185+
return
186+
187+
# 消息提取
188+
msg = Message(msg)
140189

141-
if we_type in ["Text", "Card"]:
142-
my.send(str(we_text), toUserName=my.to_user_name)
143-
elif we_type == "Sharing":
144-
my.send(we_text + "\n" + msg_url, toUserName=my.to_user_name)
145-
elif we_type == "Recording":
146-
my.send_file(".Cache/" + msg_file, toUserName=my.to_user_name)
147-
elif we_type == "Picture" and (not msg_file.endswith(".gif")):
148-
my.send_image(".Cache/" + msg_file, toUserName=my.to_user_name)
190+
# 处理群消息
191+
if msg.from_user_name.startswith("@@"):
192+
process_message_group(msg)
149193

194+
# 处理撤回消息
195+
process_message_revoke(msg)
150196
return
151197

152198

@@ -332,4 +378,75 @@ def text_reply(msg):
332378
'Type': 'Text',
333379
'Text': '就是那个,那个协议我们手上有吗'
334380
}
381+
382+
警示消息:好友类
383+
{
384+
'MsgId': '1529895072288746571',
385+
'FromUserName': '@4076708be2e09ef83f249f168553d0dd55b4f734aee7d276e92ddbe98625476a',
386+
'ToUserName': '@f97583d8ffbaee6189854116897c677f',
387+
'MsgType': 10000,
388+
'Content': '你已添加了呼啸而过的小青春,现在可以开始聊天了。',
389+
'Status': 4,
390+
'ImgStatus': 1,
391+
'CreateTime': 1498533407,
392+
'VoiceLength': 0,
393+
'PlayLength': 0,
394+
'FileName': '',
395+
'FileSize': '',
396+
'MediaId': '',
397+
'Url': '',
398+
'AppMsgType': 0,
399+
'StatusNotifyCode': 0,
400+
'StatusNotifyUserName': '',
401+
'HasProductId': 0,
402+
'Ticket': '',
403+
'ImgHeight': 0,
404+
'ImgWidth': 0,
405+
'SubMsgType': 0,
406+
'NewMsgId': 1529895072288746571,
407+
'OriContent': '',
408+
'User': <User: {
409+
'userName': '@4076708be2e09ef83f249f168553d0dd55b4f734aee7d276e92ddbe98625476a',
410+
'MemberList': <ContactList: []>
411+
}>,
412+
'Type': 'Note',
413+
'Text': '你已添加了呼啸而过的小青春,现在可以开始聊天了。'
414+
}
415+
416+
警示消息:群类
417+
{
418+
'MsgId': '1049646282086057263',
419+
'FromUserName': '@@300f57b68ca7ef593ae3221eef7dba5377466c86122aaa15a8ffc1031310e210',
420+
'ToUserName': '@006f63e8086ab07fcbe3771dc824c4a6',
421+
'MsgType': 10000,
422+
'Content': '你邀请"大姐"加入了群聊',
423+
'Status': 3,
424+
'ImgStatus': 1,
425+
'CreateTime': 1498533901,
426+
'VoiceLength': 0,
427+
'PlayLength': 0,
428+
'FileName': '',
429+
'FileSize': '',
430+
'MediaId': '',
431+
'Url': '',
432+
'AppMsgType': 0,
433+
'StatusNotifyCode': 0,
434+
'StatusNotifyUserName': '',
435+
'HasProductId': 0,
436+
'Ticket': '',
437+
'ImgHeight': 0,
438+
'ImgWidth': 0,
439+
'SubMsgType': 0,
440+
'NewMsgId': 1049646282086057263,
441+
'OriContent': '',
442+
'ActualUserName': '@006f63e8086ab07fcbe3771dc824c4a6',
443+
'ActualNickName': '某某某',
444+
'IsAt': False,
445+
'User': <Chatroom: {
446+
'UserName': '@@300f57b68ca7ef593ae3221eef7dba5377466c86122aaa15a8ffc1031310e210',
447+
'MemberList': <ContactList: []>
448+
}>,
449+
'Type': 'Note',
450+
'Text': '你邀请"大姐"加入了群聊'
451+
}
335452
"""

0 commit comments

Comments
 (0)