Browse Source

Merge branch 'master' of https://github.com/liuwons/wxBot

# Conflicts:
#	.gitignore
#	README.md
#	bot.py
#	wxbot.py
liuyuqi-dellpc 7 years ago
parent
commit
9707766070
5 changed files with 217 additions and 119 deletions
  1. 0 2
      .gitignore
  2. 7 2
      README.md
  3. 14 22
      bot.py
  4. 1 0
      test.py
  5. 195 93
      wxbot.py

+ 0 - 2
.gitignore

@@ -69,6 +69,4 @@ qr.png
 /*.jpg
 *.ini
 *.un~
-/temp/wxqr.png
 /temp
-/conf

+ 7 - 2
README.md

@@ -164,6 +164,7 @@ python test.py
 | 10 | 撤回消息 | 不可用 |
 | 11 | 空内容 | 空字符串 |
 | 12 | 红包 | 不可用 |
+| 13 | 小视频 | 字符串,视频数据的url,HTTP POST请求此url可以得到mp4文件格式的数据 |
 | 99 | 未知类型 | 不可用 |
 
 ### 4.4 群文本消息
@@ -202,6 +203,7 @@ python test.py
 | `get_head_img(id)` | 获取用户头像并保存到本地文件 ***img_[id].jpg*** ,`id` 为用户id(Web微信数据) |
 | `get_msg_img(msgid)` | 获取图像消息并保存到本地文件 ***img_[msgid].jpg*** , `msgid` 为消息id(Web微信数据) |
 | `get_voice(msgid)` | 获取语音消息并保存到本地文件 ***voice_[msgid].mp3*** , `msgid` 为消息id(Web微信数据) |
+| `get_video(msgid)` | 获取视频消息并保存到本地文件 ***video_[msgid].mp4*** , `msgid` 为消息id(Web微信数据) |
 | `get_contact_name(uid)` | 获取微信id对应的名称,返回一个可能包含 `remark_name` (备注名), `nickname` (昵称), `display_name` (群名称)的字典|
 | `send_msg_by_uid(word, dst)` | 向好友发送消息,`word` 为消息字符串,`dst` 为好友用户id(Web微信数据) |
 | `send_img_msg_by_uid(fpath, dst)` | 向好友发送图片消息,`fpath` 为本地图片文件路径,`dst` 为好友用户id(Web微信数据) |
@@ -267,8 +269,11 @@ python test.py
 
 [zixia/wechaty](https://github.com/zixia/wechaty) Wechaty is wechat for bot in Javascript(ES6). It's a Personal Account Robot Framework/Library.
 
-## 7 交流讨论
+## 7 基于Wxbot延伸的一些项目
+[WxbotManage](https://coding.net/u/vivre/p/WxbotManage/git) 基于Wxbot的微信多开管理和Webapi系统
+
+## 8 交流讨论
 
 问题可以直接开 **issue**
 
-**QQ** 交流群: **429134510**
+**QQ** 交流群: **429134510** (1群)  **603614392** (2群)

+ 14 - 22
bot.py

@@ -4,8 +4,7 @@
 from wxbot import *
 import ConfigParser
 import json
-import logging
-import logging.config
+
 
 class TulingWXBot(WXBot):
     def __init__(self):
@@ -16,12 +15,12 @@ class TulingWXBot(WXBot):
 
         try:
             cf = ConfigParser.ConfigParser()
-            cf.read('conf/conf.ini')
+            cf.read('conf.ini')
             self.tuling_key = cf.get('main', 'key')
         except Exception:
             pass
-        logging.info('tuling_key:'+self.tuling_key)
-# 自动回复函数self:发送方用户id, uid, msg
+        print 'tuling_key:', self.tuling_key
+
     def tuling_auto_reply(self, uid, msg):
         if self.tuling_key:
             url = "http://www.tuling123.com/openapi/api"
@@ -32,18 +31,21 @@ class TulingWXBot(WXBot):
             result = ''
             if respond['code'] == 100000:
                 result = respond['text'].replace('<br>', '  ')
+                result = result.replace(u'\xa0', u' ')
             elif respond['code'] == 200000:
                 result = respond['url']
             elif respond['code'] == 302000:
                 for k in respond['list']:
-                    result = result + u"【" + k['source'] + u"】 " + \
+                    result = result + u"【" + k['source'] + u"】 " +\
                         k['article'] + "\t" + k['detailurl'] + "\n"
             else:
                 result = respond['text'].replace('<br>', '  ')
-            logging.info('    ROBOT:'+ result)
+                result = result.replace(u'\xa0', u' ')
+
+            print '    ROBOT:', result
             return result
         else:
-            return u"知道啦,我是天问机器人,主人马上就来!"
+            return u"知道啦"
 
     def auto_switch(self, msg):
         msg_data = msg['content']['data']
@@ -59,18 +61,17 @@ class TulingWXBot(WXBot):
                 if i == msg_data:
                     self.robot_switch = True
                     self.send_msg_by_uid(u'[Robot]' + u'机器人已开启!', msg['to_user_id'])
-# msg   dict: {'content': {'data': u'\u53bb', 'type': 0}, 'msg_id': u'3808887025959048251', 'msg_type_id': 4, 'to_user_id': u'@97745d23f2d3bbe5241cede14a3d8baa45809a1842e762b5a33fc1353f6efa3a', 'user': {'id': u'@f95a572b1284a0f75dd550a4ed9a93d788ded42a856db023cd3494faab623311', 'name': u'\u5929\u95ee'}}
+
     def handle_msg_all(self, msg):
         if not self.robot_switch and msg['msg_type_id'] != 1:
             return
         if msg['msg_type_id'] == 1 and msg['content']['type'] == 0:  # reply to self
             self.auto_switch(msg)
-            # msg_type_id=4 发送文字
         elif msg['msg_type_id'] == 4 and msg['content']['type'] == 0:  # text message from contact
             self.send_msg_by_uid(self.tuling_auto_reply(msg['user']['id'], msg['content']['data']), msg['user']['id'])
         elif msg['msg_type_id'] == 3 and msg['content']['type'] == 0:  # group text message
             if 'detail' in msg['content']:
-                my_names = self.get_group_member_name(self.my_account['UserName'], msg['user']['id'])
+                my_names = self.get_group_member_name(msg['user']['id'], self.my_account['UserName'])
                 if my_names is None:
                     my_names = {}
                 if 'NickName' in self.my_account and self.my_account['NickName']:
@@ -93,18 +94,9 @@ class TulingWXBot(WXBot):
                     else:
                         reply += u"对不起,只认字,其他杂七杂八的我都不认识,,,Ծ‸Ծ,,"
                     self.send_msg_by_uid(reply, msg['user']['id'])
-        else:
-            src_name = msg['user']['name']
-            reply = 'to ' + src_name + ': '
-            reply += u"主人马上就来!"
-            #self.send_msg_by_uid(reply, msg['user']['id'])
-
-'''
-主函数,执行TulingWXBot类里面的run方法
-'''
+
+
 def main():
-    logging.config.fileConfig("conf/logger.conf")
-    logger=logging.getLogger("example01")
     bot = TulingWXBot()
     bot.DEBUG = True
     bot.conf['qr'] = 'png'

+ 1 - 0
test.py

@@ -1,5 +1,6 @@
 #!/usr/bin/env python
 # coding: utf-8
+#
 
 from wxbot import *
 

+ 195 - 93
wxbot.py

@@ -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)