|
@@ -17,8 +17,6 @@ import random
|
|
|
from traceback import format_exc
|
|
|
from requests.exceptions import ConnectionError, ReadTimeout
|
|
|
import HTMLParser
|
|
|
-import logging
|
|
|
-import logging.config
|
|
|
|
|
|
UNKONWN = 'unkonwn'
|
|
|
SUCCESS = '200'
|
|
@@ -56,7 +54,7 @@ class SafeSession(requests.Session):
|
|
|
timeout,
|
|
|
allow_redirects, proxies, hooks, stream, verify, cert, json)
|
|
|
except Exception as e:
|
|
|
- logging.info(e.message, traceback.format_exc())
|
|
|
+ print e.message, traceback.format_exc()
|
|
|
continue
|
|
|
|
|
|
#重试3次以后再加一次,抛出异常
|
|
@@ -87,6 +85,8 @@ class WXBot:
|
|
|
self.sync_key = []
|
|
|
self.sync_host = ''
|
|
|
|
|
|
+ status = 'wait4login' #表示机器人状态,供WEBAPI读取,WxbotManage使用
|
|
|
+ bot_conf = {} #机器人配置,在webapi初始化的时候传入,后续也可修改,WxbotManage使用
|
|
|
|
|
|
self.batch_count = 50 #一次拉取50个联系人的信息
|
|
|
self.full_user_name_list = [] #直接获取不到通讯录时,获取的username列表
|
|
@@ -120,8 +120,21 @@ class WXBot:
|
|
|
self.encry_chat_room_id_list = [] # 存储群聊的EncryChatRoomId,获取群内成员头像时需要用到
|
|
|
|
|
|
self.file_index = 0
|
|
|
- logging.config.fileConfig("conf/logger.conf")
|
|
|
- logger = logging.getLogger("example01")
|
|
|
+
|
|
|
+ #在未传入bot_conf的情况下尝试载入本地配置文件,WxbotManage使用
|
|
|
+ def load_conf(self,bot_conf):
|
|
|
+ try:
|
|
|
+ if bot_conf == {}:
|
|
|
+ with open(os.path.join(self.temp_pwd,'bot_conf.json')) as f:
|
|
|
+ self.bot_conf= json.loads(f.read())
|
|
|
+ except:
|
|
|
+ self.bot_conf = {}
|
|
|
+
|
|
|
+ #保存配置文件,WxbotManage使用
|
|
|
+ def save_conf(self):
|
|
|
+ with open(os.path.join(self.temp_pwd,'bot_conf.json'), 'w') as f:
|
|
|
+ f.write(json.dumps(self.bot_conf))
|
|
|
+
|
|
|
|
|
|
@staticmethod
|
|
|
def to_unicode(string, encoding='utf-8'):
|
|
@@ -140,23 +153,35 @@ class WXBot:
|
|
|
|
|
|
def get_contact(self):
|
|
|
"""获取当前账户的所有相关账号(包括联系人、公众号、群聊、特殊账号)"""
|
|
|
- if self.is_big_contact:
|
|
|
- return False
|
|
|
- url = self.base_uri + '/webwxgetcontact?pass_ticket=%s&skey=%s&r=%s' \
|
|
|
+ dic_list = []
|
|
|
+ url = self.base_uri + '/webwxgetcontact?seq=0&pass_ticket=%s&skey=%s&r=%s' \
|
|
|
% (self.pass_ticket, self.skey, int(time.time()))
|
|
|
|
|
|
#如果通讯录联系人过多,这里会直接获取失败
|
|
|
try:
|
|
|
- r = self.session.post(url, data='{}')
|
|
|
+ r = self.session.post(url, data='{}', timeout=180)
|
|
|
except Exception as e:
|
|
|
- self.is_big_contact = True
|
|
|
return False
|
|
|
r.encoding = 'utf-8'
|
|
|
+ dic = json.loads(r.text)
|
|
|
+ dic_list.append(dic)
|
|
|
+
|
|
|
+ while int(dic["Seq"]) != 0:
|
|
|
+ print "[INFO] Geting contacts. Get %s contacts for now" % dic["MemberCount"]
|
|
|
+ url = self.base_uri + '/webwxgetcontact?seq=%s&pass_ticket=%s&skey=%s&r=%s' \
|
|
|
+ % (dic["Seq"], self.pass_ticket, self.skey, int(time.time()))
|
|
|
+ r = self.session.post(url, data='{}', timeout=180)
|
|
|
+ r.encoding = 'utf-8'
|
|
|
+ dic = json.loads(r.text)
|
|
|
+ dic_list.append(dic)
|
|
|
+
|
|
|
if self.DEBUG:
|
|
|
with open(os.path.join(self.temp_pwd,'contacts.json'), 'w') as f:
|
|
|
- f.write(r.text.encode('utf-8'))
|
|
|
- dic = json.loads(r.text)
|
|
|
- self.member_list = dic['MemberList']
|
|
|
+ f.write(json.dumps(dic_list))
|
|
|
+
|
|
|
+ self.member_list = []
|
|
|
+ for dic in dic_list:
|
|
|
+ self.member_list.extend(dic['MemberList'])
|
|
|
|
|
|
special_users = ['newsapp', 'fmessage', 'filehelper', 'weibo', 'qqmail',
|
|
|
'fmessage', 'tmessage', 'qmessage', 'qqsync', 'floatbottle',
|
|
@@ -224,7 +249,7 @@ class WXBot:
|
|
|
self.cursor += self.batch_count
|
|
|
cur_batch = map(map_username_batch, cur_batch)
|
|
|
user_info_list += self.batch_get_contact(cur_batch)
|
|
|
- logging.info("[INFO] Get batch contacts")
|
|
|
+ print "[INFO] Get batch contacts"
|
|
|
|
|
|
self.member_list = user_info_list
|
|
|
special_users = ['newsapp', 'filehelper', 'weibo', 'qqmail',
|
|
@@ -286,8 +311,8 @@ class WXBot:
|
|
|
f.write(json.dumps(self.group_members))
|
|
|
with open(os.path.join(self.temp_pwd,'account_info.json'), 'w') as f:
|
|
|
f.write(json.dumps(self.account_info))
|
|
|
- logging.info('[INFO] Get %d contacts' % len(self.contact_list))
|
|
|
- logging.info('[INFO] Start to process messages .')
|
|
|
+ print '[INFO] Get %d contacts' % len(self.contact_list)
|
|
|
+ print '[INFO] Start to process messages .'
|
|
|
return True
|
|
|
|
|
|
|
|
@@ -540,7 +565,7 @@ class WXBot:
|
|
|
msg_content['data'] = pos
|
|
|
msg_content['detail'] = data
|
|
|
if self.DEBUG:
|
|
|
- logging.info(' %s[Location] %s ' % (msg_prefix, pos))
|
|
|
+ print ' %s[Location] %s ' % (msg_prefix, pos)
|
|
|
else:
|
|
|
msg_content['type'] = 0
|
|
|
if msg_type_id == 3 or (msg_type_id == 1 and msg['ToUserName'][:2] == '@@'): # Group text message
|
|
@@ -555,28 +580,28 @@ class WXBot:
|
|
|
msg_content['data'] = content
|
|
|
if self.DEBUG:
|
|
|
try:
|
|
|
- logging.info(' %s[Text] %s' % (msg_prefix, msg_content['data']))
|
|
|
+ print ' %s[Text] %s' % (msg_prefix, msg_content['data'])
|
|
|
except UnicodeEncodeError:
|
|
|
- logging.info(' %s[Text] (illegal text).' % msg_prefix)
|
|
|
+ print ' %s[Text] (illegal text).' % msg_prefix
|
|
|
elif mtype == 3:
|
|
|
msg_content['type'] = 3
|
|
|
msg_content['data'] = self.get_msg_img_url(msg_id)
|
|
|
msg_content['img'] = self.session.get(msg_content['data']).content.encode('hex')
|
|
|
if self.DEBUG:
|
|
|
image = self.get_msg_img(msg_id)
|
|
|
- logging.info(' %s[Image] %s' % (msg_prefix, image))
|
|
|
+ print ' %s[Image] %s' % (msg_prefix, image)
|
|
|
elif mtype == 34:
|
|
|
msg_content['type'] = 4
|
|
|
msg_content['data'] = self.get_voice_url(msg_id)
|
|
|
msg_content['voice'] = self.session.get(msg_content['data']).content.encode('hex')
|
|
|
if self.DEBUG:
|
|
|
voice = self.get_voice(msg_id)
|
|
|
- logging.info(' %s[Voice] %s' % (msg_prefix, voice))
|
|
|
+ print ' %s[Voice] %s' % (msg_prefix, voice)
|
|
|
elif mtype == 37:
|
|
|
msg_content['type'] = 37
|
|
|
msg_content['data'] = msg['RecommendInfo']
|
|
|
if self.DEBUG:
|
|
|
- logging.info(' %s[useradd] %s' % (msg_prefix,msg['RecommendInfo']['NickName']))
|
|
|
+ print ' %s[useradd] %s' % (msg_prefix,msg['RecommendInfo']['NickName'])
|
|
|
elif mtype == 42:
|
|
|
msg_content['type'] = 5
|
|
|
info = msg['RecommendInfo']
|
|
@@ -586,19 +611,18 @@ class WXBot:
|
|
|
'city': info['City'],
|
|
|
'gender': ['unknown', 'male', 'female'][info['Sex']]}
|
|
|
if self.DEBUG:
|
|
|
- logging.info(' %s[Recommend]' % msg_prefix)
|
|
|
- logging.info(' -----------------------------')
|
|
|
- logging.info(' | NickName: %s' % info['NickName'])
|
|
|
- logging.info(' | NickName: %s' % info['NickName'])
|
|
|
- logging.info(' | Alias: %s' % info['Alias'])
|
|
|
- logging.info(' | Local: %s %s' % (info['Province'], info['City']))
|
|
|
- logging.info(' | Gender: %s' % ['unknown', 'male', 'female'][info['Sex']])
|
|
|
- logging.info(' -----------------------------')
|
|
|
+ print ' %s[Recommend]' % msg_prefix
|
|
|
+ print ' -----------------------------'
|
|
|
+ print ' | NickName: %s' % info['NickName']
|
|
|
+ print ' | Alias: %s' % info['Alias']
|
|
|
+ print ' | Local: %s %s' % (info['Province'], info['City'])
|
|
|
+ print ' | Gender: %s' % ['unknown', 'male', 'female'][info['Sex']]
|
|
|
+ print ' -----------------------------'
|
|
|
elif mtype == 47:
|
|
|
msg_content['type'] = 6
|
|
|
msg_content['data'] = self.search_content('cdnurl', content)
|
|
|
if self.DEBUG:
|
|
|
- logging.info(' %s[Animation] %s' % (msg_prefix, msg_content['data']))
|
|
|
+ print ' %s[Animation] %s' % (msg_prefix, msg_content['data'])
|
|
|
elif mtype == 49:
|
|
|
msg_content['type'] = 7
|
|
|
if msg['AppMsgType'] == 3:
|
|
@@ -617,39 +641,45 @@ class WXBot:
|
|
|
'content': msg.get('Content') # 有的公众号会发一次性3 4条链接一个大图,如果只url那只能获取第一条,content里面有所有的链接
|
|
|
}
|
|
|
if self.DEBUG:
|
|
|
- logging.info(' %s[Share] %s' % (msg_prefix, app_msg_type))
|
|
|
- logging.info(' --------------------------')
|
|
|
- logging.info(' | title: %s' % msg['FileName'])
|
|
|
- logging.info(' | desc: %s' % self.search_content('des', content, 'xml'))
|
|
|
- logging.info(' | link: %s' % msg['Url'])
|
|
|
- logging.info(' | from: %s' % self.search_content('appname', content, 'xml'))
|
|
|
- logging.info(' | content: %s' % (msg.get('content')[:20] if msg.get('content') else "unknown"))
|
|
|
- logging.info(' --------------------------')
|
|
|
+ print ' %s[Share] %s' % (msg_prefix, app_msg_type)
|
|
|
+ print ' --------------------------'
|
|
|
+ print ' | title: %s' % msg['FileName']
|
|
|
+ print ' | desc: %s' % self.search_content('des', content, 'xml')
|
|
|
+ print ' | link: %s' % msg['Url']
|
|
|
+ print ' | from: %s' % self.search_content('appname', content, 'xml')
|
|
|
+ print ' | content: %s' % (msg.get('content')[:20] if msg.get('content') else "unknown")
|
|
|
+ print ' --------------------------'
|
|
|
+
|
|
|
elif mtype == 62:
|
|
|
msg_content['type'] = 8
|
|
|
msg_content['data'] = content
|
|
|
if self.DEBUG:
|
|
|
- logging.info(' %s[Video] Please check on mobiles' % msg_prefix)
|
|
|
+ print ' %s[Video] Please check on mobiles' % msg_prefix
|
|
|
elif mtype == 53:
|
|
|
msg_content['type'] = 9
|
|
|
msg_content['data'] = content
|
|
|
if self.DEBUG:
|
|
|
- logging.info(' %s[Video Call]' % msg_prefix)
|
|
|
+ print ' %s[Video Call]' % msg_prefix
|
|
|
elif mtype == 10002:
|
|
|
msg_content['type'] = 10
|
|
|
msg_content['data'] = content
|
|
|
if self.DEBUG:
|
|
|
- logging.info(' %s[Redraw]' % msg_prefix)
|
|
|
+ print ' %s[Redraw]' % msg_prefix
|
|
|
elif mtype == 10000: # unknown, maybe red packet, or group invite
|
|
|
msg_content['type'] = 12
|
|
|
msg_content['data'] = msg['Content']
|
|
|
if self.DEBUG:
|
|
|
- logging.info(' [Unknown]')
|
|
|
+ print ' [Unknown]'
|
|
|
+ elif mtype == 43:
|
|
|
+ msg_content['type'] = 13
|
|
|
+ msg_content['data'] = self.get_video_url(msg_id)
|
|
|
+ if self.DEBUG:
|
|
|
+ print ' %s[video] %s' % (msg_prefix, msg_content['data'])
|
|
|
else:
|
|
|
msg_content['type'] = 99
|
|
|
msg_content['data'] = content
|
|
|
if self.DEBUG:
|
|
|
- logging.info(' %s[Unknown]' % msg_prefix)
|
|
|
+ print ' %s[Unknown]' % msg_prefix
|
|
|
return msg_content
|
|
|
|
|
|
def handle_msg(self, r):
|
|
@@ -678,9 +708,9 @@ class WXBot:
|
|
|
with open(os.path.join(self.temp_pwd,'UserName.txt'), 'w') as f:
|
|
|
f.write(msg['StatusNotifyUserName'])
|
|
|
with open(os.path.join(self.temp_pwd,'wxid.txt'), 'w') as f:
|
|
|
- f.write(wxid_str)
|
|
|
- logging.info("[INFO] Contact list is too big. Now start to fetch member list .")
|
|
|
- self.get_big_contact()
|
|
|
+ f.write(json.dumps(self.wxid_list))
|
|
|
+ print "[INFO] Contact list is too big. Now start to fetch member list ."
|
|
|
+ #self.get_big_contact()
|
|
|
|
|
|
elif msg['MsgType'] == 37: # friend request
|
|
|
msg_type_id = 37
|
|
@@ -719,7 +749,7 @@ class WXBot:
|
|
|
user['name'] = HTMLParser.HTMLParser().unescape(user['name'])
|
|
|
|
|
|
if self.DEBUG and msg_type_id != 0:
|
|
|
- logging.info(u'[MSG] %s:' % user['name'])
|
|
|
+ print u'[MSG] %s:' % user['name']
|
|
|
content = self.extract_msg_content(msg_type_id, msg)
|
|
|
message = {'msg_type_id': msg_type_id,
|
|
|
'msg_id': msg['MsgId'],
|
|
@@ -737,7 +767,10 @@ class WXBot:
|
|
|
|
|
|
def proc_msg(self):
|
|
|
self.test_sync_check()
|
|
|
+ self.status = 'loginsuccess' #WxbotManage使用
|
|
|
while True:
|
|
|
+ if self.status == 'wait4loginout': #WxbotManage使用
|
|
|
+ return
|
|
|
check_time = time.time()
|
|
|
try:
|
|
|
[retcode, selector] = self.sync_check()
|
|
@@ -770,17 +803,17 @@ class WXBot:
|
|
|
elif selector == '0': # 无事件
|
|
|
pass
|
|
|
else:
|
|
|
- logging.info('[DEBUG] sync_check:', retcode, selector)
|
|
|
+ print '[DEBUG] sync_check:', retcode, selector
|
|
|
r = self.sync()
|
|
|
if r is not None:
|
|
|
self.handle_msg(r)
|
|
|
else:
|
|
|
- logging.info('[DEBUG] sync_check:', retcode, selector)
|
|
|
+ print '[DEBUG] sync_check:', retcode, selector
|
|
|
time.sleep(10)
|
|
|
self.schedule()
|
|
|
except:
|
|
|
- logging.info('[ERROR] Except in proc_msg')
|
|
|
- logging.info(format_exc())
|
|
|
+ print '[ERROR] Except in proc_msg'
|
|
|
+ print format_exc()
|
|
|
check_time = time.time() - check_time
|
|
|
if check_time < 0.8:
|
|
|
time.sleep(1 - check_time)
|
|
@@ -858,14 +891,57 @@ class WXBot:
|
|
|
gid = group['UserName']
|
|
|
if gid == '':
|
|
|
return False
|
|
|
+ #获取群成员数量并判断邀请方式
|
|
|
+ group_num=len(self.group_members[gid])
|
|
|
+ print '[DEBUG] group_name:%s group_num:%s' % (group_name,group_num)
|
|
|
#通过群id判断uid是否在群中
|
|
|
for user in self.group_members[gid]:
|
|
|
if user['UserName'] == uid:
|
|
|
#已经在群里面了,不用加了
|
|
|
return True
|
|
|
- url = self.base_uri + '/webwxupdatechatroom?fun=addmember&pass_ticket=%s' % self.pass_ticket
|
|
|
- params ={
|
|
|
- "AddMemberList": uid,
|
|
|
+ if group_num<=100:
|
|
|
+ url = self.base_uri + '/webwxupdatechatroom?fun=addmember&pass_ticket=%s' % self.pass_ticket
|
|
|
+ params ={
|
|
|
+ "AddMemberList": uid,
|
|
|
+ "ChatRoomName": gid,
|
|
|
+ "BaseRequest": self.base_request
|
|
|
+ }
|
|
|
+ else:
|
|
|
+ url = self.base_uri + '/webwxupdatechatroom?fun=invitemember'
|
|
|
+ params ={
|
|
|
+ "InviteMemberList": uid,
|
|
|
+ "ChatRoomName": gid,
|
|
|
+ "BaseRequest": self.base_request
|
|
|
+ }
|
|
|
+ headers = {'content-type': 'application/json; charset=UTF-8'}
|
|
|
+ data = json.dumps(params, ensure_ascii=False).encode('utf8')
|
|
|
+ try:
|
|
|
+ r = self.session.post(url, data=data, headers=headers)
|
|
|
+ except (ConnectionError, ReadTimeout):
|
|
|
+ return False
|
|
|
+ dic = r.json()
|
|
|
+ return dic['BaseResponse']['Ret'] == 0
|
|
|
+
|
|
|
+ def invite_friend_to_group(self,uid,group_name):
|
|
|
+ """
|
|
|
+ 将好友加入到群中。对人数多的群,需要调用此方法。
|
|
|
+ 拉人时,可以先尝试使用add_friend_to_group方法,当调用失败(Ret=1)时,再尝试调用此方法。
|
|
|
+ """
|
|
|
+ gid = ''
|
|
|
+ # 通过群名获取群id,群没保存到通讯录中的话无法添加哦
|
|
|
+ for group in self.group_list:
|
|
|
+ if group['NickName'] == group_name:
|
|
|
+ gid = group['UserName']
|
|
|
+ if gid == '':
|
|
|
+ return False
|
|
|
+ # 通过群id判断uid是否在群中
|
|
|
+ for user in self.group_members[gid]:
|
|
|
+ if user['UserName'] == uid:
|
|
|
+ # 已经在群里面了,不用加了
|
|
|
+ return True
|
|
|
+ url = self.base_uri + '/webwxupdatechatroom?fun=invitemember&pass_ticket=%s' % self.pass_ticket
|
|
|
+ params = {
|
|
|
+ "InviteMemberList": uid,
|
|
|
"ChatRoomName": gid,
|
|
|
"BaseRequest": self.base_request
|
|
|
}
|
|
@@ -948,7 +1024,7 @@ class WXBot:
|
|
|
|
|
|
def upload_media(self, fpath, is_img=False):
|
|
|
if not os.path.exists(fpath):
|
|
|
- logging.info('[ERROR] File not exists.')
|
|
|
+ print '[ERROR] File not exists.'
|
|
|
return None
|
|
|
url_1 = 'https://file.'+self.base_host+'/cgi-bin/mmwebwx-bin/webwxuploadmedia?f=json'
|
|
|
url_2 = 'https://file2.'+self.base_host+'/cgi-bin/mmwebwx-bin/webwxuploadmedia?f=json'
|
|
@@ -980,7 +1056,7 @@ class WXBot:
|
|
|
# 当file返回值不为0时则为上传失败,尝试第二服务器上传
|
|
|
r = self.session.post(url_2, files=files)
|
|
|
if json.loads(r.text)['BaseResponse']['Ret'] != 0:
|
|
|
- logging.info('[ERROR] Upload media failure.')
|
|
|
+ print '[ERROR] Upload media failure.'
|
|
|
return None
|
|
|
mid = json.loads(r.text)['MediaId']
|
|
|
return mid
|
|
@@ -1069,7 +1145,7 @@ class WXBot:
|
|
|
result = True
|
|
|
for line in f.readlines():
|
|
|
line = line.replace('\n', '')
|
|
|
- logging.info('-> ' + name + ': ' + line)
|
|
|
+ print '-> ' + name + ': ' + line
|
|
|
if self.send_msg_by_uid(line, uid):
|
|
|
pass
|
|
|
else:
|
|
@@ -1084,7 +1160,7 @@ class WXBot:
|
|
|
return False
|
|
|
else:
|
|
|
if self.DEBUG:
|
|
|
- logging.info('[ERROR] This user does not exist .')
|
|
|
+ print '[ERROR] This user does not exist .'
|
|
|
return True
|
|
|
|
|
|
@staticmethod
|
|
@@ -1100,32 +1176,41 @@ class WXBot:
|
|
|
return 'unknown'
|
|
|
|
|
|
def run(self):
|
|
|
- self.get_uuid()
|
|
|
- self.gen_qr_code(os.path.join(self.temp_pwd,'wxqr.png'))
|
|
|
- logging.info('[INFO] Please use WeChat to scan the QR code .')
|
|
|
+ try:
|
|
|
+ self.get_uuid()
|
|
|
+ self.gen_qr_code(os.path.join(self.temp_pwd,'wxqr.png'))
|
|
|
+ print '[INFO] Please use WeChat to scan the QR code .'
|
|
|
+
|
|
|
+ result = self.wait4login()
|
|
|
+ if result != SUCCESS:
|
|
|
+ print '[ERROR] Web WeChat login failed. failed code=%s' % (result,)
|
|
|
+ self.status = 'loginout'
|
|
|
+ return
|
|
|
+
|
|
|
+ if self.login():
|
|
|
+ print '[INFO] Web WeChat login succeed .'
|
|
|
+ else:
|
|
|
+ print '[ERROR] Web WeChat login failed .'
|
|
|
+ self.status = 'loginout'
|
|
|
+ return
|
|
|
|
|
|
- result = self.wait4login()
|
|
|
- if result != SUCCESS:
|
|
|
- logging.info('[ERROR] Web WeChat login failed. failed code=%s' % (result,))
|
|
|
- return
|
|
|
+ if self.init():
|
|
|
+ print '[INFO] Web WeChat init succeed .'
|
|
|
+ else:
|
|
|
+ print '[INFO] Web WeChat init failed'
|
|
|
+ self.status = 'loginout'
|
|
|
+ return
|
|
|
+ self.status_notify()
|
|
|
+ if self.get_contact():
|
|
|
+ print '[INFO] Get %d contacts' % len(self.contact_list)
|
|
|
+ print '[INFO] Start to process messages .'
|
|
|
+ self.proc_msg()
|
|
|
+ self.status = 'loginout'
|
|
|
+ except Exception,e:
|
|
|
+ print '[ERROR] Web WeChat run failed --> %s'%(e)
|
|
|
+ self.status = 'loginout'
|
|
|
|
|
|
- if self.login():
|
|
|
- logging.info('[INFO] Web WeChat login succeed .')
|
|
|
- else:
|
|
|
- logging.info('[ERROR] Web WeChat login failed .')
|
|
|
- return
|
|
|
|
|
|
- if self.init():
|
|
|
- logging.info('[INFO] Web WeChat init succeed .')
|
|
|
- else:
|
|
|
- logging.info('[INFO] Web WeChat init failed')
|
|
|
- return
|
|
|
- self.status_notify()
|
|
|
- if self.get_contact():
|
|
|
- logging.info('[INFO] Get %d contacts' % len(self.contact_list))
|
|
|
- logging.info('[INFO] Start to process messages .')
|
|
|
- self.proc_msg()
|
|
|
-#第一步:获取uuid
|
|
|
def get_uuid(self):
|
|
|
url = 'https://login.weixin.qq.com/jslogin'
|
|
|
params = {
|
|
@@ -1137,7 +1222,6 @@ class WXBot:
|
|
|
r = self.session.get(url, params=params)
|
|
|
r.encoding = 'utf-8'
|
|
|
data = r.text
|
|
|
- #window.QRLogin.code = 200; window.QRLogin.uuid = "AfJkWJ4bxg==";
|
|
|
regx = r'window.QRLogin.code = (\d+); window.QRLogin.uuid = "(\S+?)"'
|
|
|
pm = re.search(regx, data)
|
|
|
if pm:
|
|
@@ -1145,7 +1229,7 @@ class WXBot:
|
|
|
self.uuid = pm.group(2)
|
|
|
return code == '200'
|
|
|
return False
|
|
|
-#第二步:拼凑二维码链接
|
|
|
+
|
|
|
def gen_qr_code(self, qr_file_path):
|
|
|
string = 'https://login.weixin.qq.com/l/' + self.uuid
|
|
|
qr = pyqrcode.create(string)
|
|
@@ -1155,8 +1239,8 @@ class WXBot:
|
|
|
# img = Image.open(qr_file_path)
|
|
|
# img.show()
|
|
|
elif self.conf['qr'] == 'tty':
|
|
|
- logging.info(qr.terminal(quiet_zone=1))
|
|
|
-
|
|
|
+ print(qr.terminal(quiet_zone=1))
|
|
|
+
|
|
|
def do_request(self, url):
|
|
|
r = self.session.get(url)
|
|
|
r.encoding = 'utf-8'
|
|
@@ -1173,7 +1257,6 @@ class WXBot:
|
|
|
408: timeout
|
|
|
tip=0, 等待用户确认登录,
|
|
|
200: confirmed
|
|
|
- https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=YeCkBn4EEg==&tip=0&r=-301174534&_=1482064866062
|
|
|
"""
|
|
|
LOGIN_TEMPLATE = 'https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login?tip=%s&uuid=%s&_=%s'
|
|
|
tip = 1
|
|
@@ -1188,7 +1271,7 @@ class WXBot:
|
|
|
url = LOGIN_TEMPLATE % (tip, self.uuid, int(time.time()))
|
|
|
code, data = self.do_request(url)
|
|
|
if code == SCANED:
|
|
|
- logging.info('[INFO] Please confirm to login .')
|
|
|
+ print '[INFO] Please confirm to login .'
|
|
|
tip = 0
|
|
|
elif code == SUCCESS: # 确认登录成功
|
|
|
param = re.search(r'window.redirect_uri="(\S+?)";', data)
|
|
@@ -1199,13 +1282,13 @@ class WXBot:
|
|
|
self.base_host = temp_host[:temp_host.find("/")]
|
|
|
return code
|
|
|
elif code == TIMEOUT:
|
|
|
- logging.info('[ERROR] WeChat login timeout. retry in %s secs later...' % (try_later_secs,))
|
|
|
+ print '[ERROR] WeChat login timeout. retry in %s secs later...' % (try_later_secs,)
|
|
|
|
|
|
tip = 1 # 重置
|
|
|
retry_time -= 1
|
|
|
time.sleep(try_later_secs)
|
|
|
else:
|
|
|
- logging.info('[ERROR] WeChat login exception return_code=%s. retry in %s secs later...' %
|
|
|
+ print ('[ERROR] WeChat login exception return_code=%s. retry in %s secs later...' %
|
|
|
(code, try_later_secs))
|
|
|
tip = 1
|
|
|
retry_time -= 1
|
|
@@ -1215,7 +1298,7 @@ class WXBot:
|
|
|
|
|
|
def login(self):
|
|
|
if len(self.redirect_uri) < 4:
|
|
|
- logging.info('[ERROR] Login failed due to network problem, please try again.')
|
|
|
+ print '[ERROR] Login failed due to network problem, please try again.'
|
|
|
return False
|
|
|
r = self.session.get(self.redirect_uri)
|
|
|
r.encoding = 'utf-8'
|
|
@@ -1283,7 +1366,7 @@ class WXBot:
|
|
|
if retcode == '0':
|
|
|
return True
|
|
|
return False
|
|
|
-#服务器轮值,获取新消息
|
|
|
+
|
|
|
def sync_check(self):
|
|
|
params = {
|
|
|
'r': int(time.time()),
|
|
@@ -1319,7 +1402,7 @@ class WXBot:
|
|
|
r.encoding = 'utf-8'
|
|
|
dic = json.loads(r.text)
|
|
|
if dic['BaseResponse']['Ret'] == 0:
|
|
|
- self.sync_key = dic['SyncKey']
|
|
|
+ self.sync_key = dic['SyncCheckKey']
|
|
|
self.sync_key_str = '|'.join([str(keyVal['Key']) + '_' + str(keyVal['Val'])
|
|
|
for keyVal in self.sync_key['List']])
|
|
|
return dic
|
|
@@ -1390,6 +1473,25 @@ class WXBot:
|
|
|
with open(os.path.join(self.temp_pwd,fn), 'wb') as f:
|
|
|
f.write(data)
|
|
|
return fn
|
|
|
+
|
|
|
+ def get_video_url(self, msgid):
|
|
|
+ return self.base_uri + '/webwxgetvideo?msgid=%s&skey=%s' % (msgid, self.skey)
|
|
|
+
|
|
|
+ def get_video(self, msgid):
|
|
|
+ """
|
|
|
+ 获取视频消息,下载视频到本地
|
|
|
+ :param msgid: 视频消息id
|
|
|
+ :return: 保存的本地视频文件路径
|
|
|
+ """
|
|
|
+ url = self.base_uri + '/webwxgetvideo?msgid=%s&skey=%s' % (msgid, self.skey)
|
|
|
+ headers = {'Range': 'bytes=0-'}
|
|
|
+ r = self.session.get(url, headers=headers)
|
|
|
+ data = r.content
|
|
|
+ fn = 'video_' + msgid + '.mp4'
|
|
|
+ with open(os.path.join(self.temp_pwd,fn), 'wb') as f:
|
|
|
+ f.write(data)
|
|
|
+ return fn
|
|
|
+
|
|
|
def set_remarkname(self,uid,remarkname):#设置联系人的备注名
|
|
|
url = self.base_uri + '/webwxoplog?lang=zh_CN&pass_ticket=%s' \
|
|
|
% (self.pass_ticket)
|