Skip to content

Commit dcb44ee

Browse files
committed
修复了通讯录过大,无法获取通讯录的问题
1 parent 60b2da5 commit dcb44ee

File tree

2 files changed

+140
-4
lines changed

2 files changed

+140
-4
lines changed

test.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ def main():
2121
bot = MyWXBot()
2222
bot.DEBUG = True
2323
bot.conf['qr'] = 'png'
24+
bot.is_big_contact = False #如果确定通讯录过大,无法获取,可以直接配置,跳过检查。假如不是过大的话,这个方法可能无法获取所有的联系人
2425
bot.run()
2526

2627

wxbot.py

Lines changed: 139 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,16 @@
1717
from traceback import format_exc
1818
from requests.exceptions import ConnectionError, ReadTimeout
1919
import HTMLParser
20+
import xml.etree.ElementTree as ET
2021

2122
UNKONWN = 'unkonwn'
2223
SUCCESS = '200'
2324
SCANED = '201'
2425
TIMEOUT = '408'
2526

27+
def map_username_batch(user_name):
28+
return {"UserName": user_name, "EncryChatRoomId": ""}
29+
2630

2731
def show_image(file_path):
2832
"""
@@ -54,6 +58,14 @@ def request(self, method, url, params=None, data=None, headers=None, cookies=Non
5458
print e.message, traceback.format_exc()
5559
continue
5660

61+
#重试3次以后再加一次,抛出异常
62+
try:
63+
return super(SafeSession, self).request(method, url, params, data, headers, cookies, files, auth,
64+
timeout,
65+
allow_redirects, proxies, hooks, stream, verify, cert, json)
66+
except Exception as e:
67+
raise e
68+
5769

5870
class WXBot:
5971
"""WXBot功能类"""
@@ -74,6 +86,12 @@ def __init__(self):
7486
self.sync_key = []
7587
self.sync_host = ''
7688

89+
90+
self.batch_count = 50 #一次拉取50个联系人的信息
91+
self.full_user_name_list = [] #直接获取不到通讯录时,获取的username列表
92+
self.wxid_list = [] #获取到的wxid的列表
93+
self.cursor = 0 #拉取联系人信息的游标
94+
self.is_big_contact = False #通讯录人数过多,无法直接获取
7795
#文件缓存目录
7896
self.temp_pwd = os.path.join(os.getcwd(),'temp')
7997
if os.path.exists(self.temp_pwd) == False:
@@ -119,9 +137,17 @@ def to_unicode(string, encoding='utf-8'):
119137

120138
def get_contact(self):
121139
"""获取当前账户的所有相关账号(包括联系人、公众号、群聊、特殊账号)"""
140+
if self.is_big_contact:
141+
return False
122142
url = self.base_uri + '/webwxgetcontact?pass_ticket=%s&skey=%s&r=%s' \
123143
% (self.pass_ticket, self.skey, int(time.time()))
124-
r = self.session.post(url, data='{}')
144+
145+
#如果通讯录联系人过多,这里会直接获取失败
146+
try:
147+
r = self.session.post(url, data='{}')
148+
except Exception as e:
149+
self.is_big_contact = True
150+
return False
125151
r.encoding = 'utf-8'
126152
if self.DEBUG:
127153
with open(os.path.join(self.temp_pwd,'contacts.json'), 'w') as f:
@@ -184,6 +210,100 @@ def get_contact(self):
184210
f.write(json.dumps(self.account_info))
185211
return True
186212

213+
214+
def get_big_contact(self):
215+
total_len = len(self.full_user_name_list)
216+
user_info_list = []
217+
218+
#一次拉取50个联系人的信息,包括所有的群聊,公众号,好友
219+
while self.cursor < total_len:
220+
cur_batch = self.full_user_name_list[self.cursor:(self.cursor+self.batch_count)]
221+
self.cursor += self.batch_count
222+
cur_batch = map(map_username_batch, cur_batch)
223+
user_info_list += self.batch_get_contact(cur_batch)
224+
print "[INFO] Get batch contacts"
225+
226+
self.member_list = user_info_list
227+
special_users = ['newsapp', 'filehelper', 'weibo', 'qqmail',
228+
'fmessage', 'tmessage', 'qmessage', 'qqsync', 'floatbottle',
229+
'lbsapp', 'shakeapp', 'medianote', 'qqfriend', 'readerapp',
230+
'blogapp', 'facebookapp', 'masssendapp', 'meishiapp',
231+
'feedsapp', 'voip', 'blogappweixin', 'weixin', 'brandsessionholder',
232+
'weixinreminder', 'wxid_novlwrv3lqwv11',
233+
'officialaccounts',
234+
'gh_22b87fa7cb3c', 'wxitil', 'userexperience_alarm', 'notification_messages', 'notifymessage']
235+
236+
self.contact_list = []
237+
self.public_list = []
238+
self.special_list = []
239+
self.group_list = []
240+
for i, contact in enumerate(self.member_list):
241+
if contact['VerifyFlag'] & 8 != 0: # 公众号
242+
self.public_list.append(contact)
243+
self.account_info['normal_member'][contact['UserName']] = {'type': 'public', 'info': contact}
244+
elif contact['UserName'] in special_users or self.wxid_list[i] in special_users: # 特殊账户
245+
self.special_list.append(contact)
246+
self.account_info['normal_member'][contact['UserName']] = {'type': 'special', 'info': contact}
247+
elif contact['UserName'].find('@@') != -1: # 群聊
248+
self.group_list.append(contact)
249+
self.account_info['normal_member'][contact['UserName']] = {'type': 'group', 'info': contact}
250+
elif contact['UserName'] == self.my_account['UserName']: # 自己
251+
self.account_info['normal_member'][contact['UserName']] = {'type': 'self', 'info': contact}
252+
else:
253+
self.contact_list.append(contact)
254+
self.account_info['normal_member'][contact['UserName']] = {'type': 'contact', 'info': contact}
255+
group_members = {}
256+
encry_chat_room_id = {}
257+
for group in self.group_list:
258+
gid = group['UserName']
259+
members = group['MemberList']
260+
group_members[gid] = members
261+
encry_chat_room_id[gid] = group['EncryChatRoomId']
262+
self.group_members = group_members
263+
self.encry_chat_room_id_list = encry_chat_room_id
264+
265+
for group in self.group_members:
266+
for member in self.group_members[group]:
267+
if member['UserName'] not in self.account_info:
268+
self.account_info['group_member'][member['UserName']] = \
269+
{'type': 'group_member', 'info': member, 'group': group}
270+
271+
if self.DEBUG:
272+
with open(os.path.join(self.temp_pwd,'contact_list.json'), 'w') as f:
273+
f.write(json.dumps(self.contact_list))
274+
with open(os.path.join(self.temp_pwd,'special_list.json'), 'w') as f:
275+
f.write(json.dumps(self.special_list))
276+
with open(os.path.join(self.temp_pwd,'group_list.json'), 'w') as f:
277+
f.write(json.dumps(self.group_list))
278+
with open(os.path.join(self.temp_pwd,'public_list.json'), 'w') as f:
279+
f.write(json.dumps(self.public_list))
280+
with open(os.path.join(self.temp_pwd,'member_list.json'), 'w') as f:
281+
f.write(json.dumps(self.member_list))
282+
with open(os.path.join(self.temp_pwd,'group_users.json'), 'w') as f:
283+
f.write(json.dumps(self.group_members))
284+
with open(os.path.join(self.temp_pwd,'account_info.json'), 'w') as f:
285+
f.write(json.dumps(self.account_info))
286+
print '[INFO] Get %d contacts' % len(self.contact_list)
287+
print '[INFO] Start to process messages .'
288+
return True
289+
290+
291+
292+
def batch_get_contact(self, cur_batch):
293+
"""批量获取成员信息"""
294+
url = self.base_uri + '/webwxbatchgetcontact?type=ex&r=%s&pass_ticket=%s' % (int(time.time()), self.pass_ticket)
295+
params = {
296+
'BaseRequest': self.base_request,
297+
"Count": len(cur_batch),
298+
"List": cur_batch
299+
}
300+
r = self.session.post(url, data=json.dumps(params))
301+
r.encoding = 'utf-8'
302+
dic = json.loads(r.text)
303+
#print dic['ContactList']
304+
return dic['ContactList']
305+
306+
187307
def batch_get_group_members(self):
188308
"""批量获取所有群聊成员信息"""
189309
url = self.base_uri + '/webwxbatchgetcontact?type=ex&r=%s&pass_ticket=%s' % (int(time.time()), self.pass_ticket)
@@ -548,6 +668,21 @@ def handle_msg(self, r):
548668
if msg['MsgType'] == 51: # init message
549669
msg_type_id = 0
550670
user['name'] = 'system'
671+
#会获取所有联系人的username 和 wxid,但是会收到3次这个消息,只取第一次
672+
if self.is_big_contact and len(self.full_user_name_list) == 0:
673+
self.full_user_name_list = msg['StatusNotifyUserName'].split(",")
674+
wxid_str = msg["Content"]
675+
tmp = wxid_str.replace("&lt;", "<")
676+
wxid_str = tmp.replace("&gt;", ">")
677+
tree = ET.fromstring(wxid_str)
678+
self.wxid_list = tree[1][1].text.split(",")
679+
with open(os.path.join(self.temp_pwd,'UserName.txt'), 'w') as f:
680+
f.write(msg['StatusNotifyUserName'])
681+
with open(os.path.join(self.temp_pwd,'wxid.txt'), 'w') as f:
682+
f.write(wxid_str)
683+
print "[INFO] Contact list is too big. Now start to fetch member list ."
684+
self.get_big_contact()
685+
551686
elif msg['MsgType'] == 37: # friend request
552687
msg_type_id = 37
553688
pass
@@ -987,9 +1122,9 @@ def run(self):
9871122
print '[INFO] Web WeChat init failed'
9881123
return
9891124
self.status_notify()
990-
self.get_contact()
991-
print '[INFO] Get %d contacts' % len(self.contact_list)
992-
print '[INFO] Start to process messages .'
1125+
if self.get_contact():
1126+
print '[INFO] Get %d contacts' % len(self.contact_list)
1127+
print '[INFO] Start to process messages .'
9931128
self.proc_msg()
9941129

9951130
def get_uuid(self):

0 commit comments

Comments
 (0)