Browse Source

Merge remote-tracking branch 'upstream/master'

gjwang 9 years ago
parent
commit
7c219e4cf7
6 changed files with 390 additions and 216 deletions
  1. 116 14
      README.md
  2. BIN
      img/backfront.jpg
  3. BIN
      img/login_on_ubuntu.png
  4. BIN
      img/send_msg.png
  5. 24 0
      test.py
  6. 250 202
      wxbot.py

+ 116 - 14
README.md

@@ -1,9 +1,11 @@
 # wxBot [![star this repo](http://github-svg-buttons.herokuapp.com/star.svg?user=liuwons&repo=wxBot&style=flat&background=1081C1)](http://github.com/liuwons/wxBot) [![fork this repo](http://github-svg-buttons.herokuapp.com/fork.svg?user=liuwons&repo=wxBot&style=flat&background=1081C1)](http://github.com/liuwons/wxBot/fork) ![python](https://img.shields.io/badge/python-2.7-ff69b4.svg)
 
-Python包装的网页微信API。可以很容易地实现微信机器人。
+Python包装Web微信实现的微信机器人框架。可以很容易地实现微信机器人。
 
-## Dependencies
-程序用到了Python requests 和 pyqrcode库,使用之前需要安装这两个库:
+## 环境与依赖
+
+目前只能运行于Python 2环境 。
+**wxBot** 用到了Python **requests** 和 **pyqrcode** 库,使用之前需要安装这两个库:
 
 ```bash
 pip install requests
@@ -11,26 +13,126 @@ pip install pyqrcode
 pip install pypng
 ```
 
-## Demo
-配置了 **[图灵机器人](http://www.tuling123.com/)** 之后,通过测试账号发送各种消息的效果:
+## 快速开发
+### 代码
 
-![向机器人发送消息](img/send_msg.png)
+利用 **wxBot** 最简单的方法就是继承WXBot类并实现handle_msg_all或者schedule函数,然后实例化子类并run,如下的代码对所有来自好友的文本消息回复 "hi", 并不断向好友tb发送"schedule"。
+handle_msg_all函数用于处理收到的每条消息,而schedule函数可以做一些任务性的事情(例如不断向好友推送信息或者一些定时任务)。
 
-![后台](img/backfront.jpg)
+```python
+#!/usr/bin/env python
+# coding: utf-8
+
+import time
+from wxbot import *
 
+class MyWXBot(WXBot):
+    def handle_msg_all(self, msg):
+        if msg['msg_type_id'] == 5 and msg['user_type'] == 'contact':
+            self.send_msg_by_uid('hi', msg['user_id'])
 
-## Run
-### 运行程序
+    def schedule(self):
+        self.send_msg('tb', 'schedule')
+        time.sleep(1)
+
+def main():
+    bot = MyWXBot()
+    bot.DEBUG = True
+    bot.run()
+
+if __name__ == '__main__':
+    main()
 
-``` bash
-python wxbot.py
 ```
 
-### 登录微信
+### 运行
 
-程序运行之后,会在当前目录下生成二维码图片文件 qr.jpg ,用微信扫描此二维码并按操作指示确认登录网页微信。可以选择是否自动回复。
+直接用python运行代码(如运行测试代码test.py):
 
+``` python
+python test.py
+```
+
+### 登录微信
+
+程序运行之后,会在当前目录下生成二维码图片文件 qr.png ,用微信扫描此二维码并按操作指示确认登录网页微信。
 
 ![1](img/1.png)
 
-按照操作指示在手机微信上扫描二维码然后登录,你可以选择是否开启自动回复模式。
+如果运行在Linux下,还可以通过设置WXBot对象的conf['qr']为'tty'的方式直接在终端打印二维码(此方法只能在Linux终端下使用),效果如下:
+
+![login_on_ubuntu](img/login_on_ubuntu.png)
+
+## 效果展示
+
+测试代码test.py的运行效果:
+
+![向机器人发送消息](img/send_msg.png)
+
+![后台](img/backfront.jpg)
+
+## 接口
+### handle_msg_all
+
+handle_msg_all函数的参数msg是代表一条消息的字典。一般包含以下字段:
+
+| 字段名 | 意义 |
+| ----- | --- |
+| user_type | 用户类型,具体见用户类型表 |
+| msg_id | 消息id,微信内部数据 |
+| msg_type_id | 消息类型,具体见消息类型表 |
+| user_id | 发送消息的用户的id,微信内部数据 |
+| user_name | 发送消息的用户的名字,为备注名或者微信用户名 |
+| content | 消息体,不同类型消息的此字段内容不同,具体见消息类型表 |
+
+用户类型表:
+
+| 类型名 | 意义 |
+| ----- | ---- |
+| contact | 好友 |
+| public | 公众号 |
+| group | 群 |
+| special | 特殊账号 |
+| unknown | 未知 |
+
+消息类型表:
+
+| 类型号 | 类型名称 | 类型描述 | content |
+| ------ | ------- | --- | -------- |
+| 1 | Location | 位置 | 字典,包含location(位置的文本描述)和xml(原始未解析的xml格式文本)字段 |
+| 2 | FileHelper | 文件 | 字符串,文本文件内容 |
+| 3 | Self | 自己发送的消息 | 字符串,文本消息 |
+| 4 | Group | 群消息 | 字典,包含group_id(微信内部id), group_name(群名), user(微信内部id), user_name(用户名称), msg(字符串消息)字段 |
+| 5 | Text | 普通文本消息 | 字符串, 文本消息 |
+| 6 | Image | 图片 | 字符串, 图片url |
+| 7 | Voice | 语音 | 字符串, 语音url |
+| 8 | Recommend | 微信名片 | 字典, 包含nickname(昵称),alias(别名),province(省份),city(城市), gender(性别)字段 |
+| 9 | Animation | 动画 | 字符串, 动画url |
+| 10 | Share | 分享 | 字典,包含type(类型),title(标题),desc(描述),url(链接),from(来自)字段 |
+| 11 | Video | 视频 | 字符串,未解析的xml字符串 |
+| 12 | VideoCall | 视频电话 | 字符串,未解析的xml字符串 |
+| 13 | Redraw | 撤回消息 | 字符串,未解析的xml字符串 |
+| 14 | Init | 微信初始化系统消息,可以忽略 | 字符串,未解析的xml字符串 |
+| 99 | Unknown | 未知类型 | 字符串,未解析的xml字符串 |
+
+### WXBot对象属性
+
+WXBot对象在登录并初始化之后,含有以下的可用数据:
+
+| 属性 | 描述 |
+| ---- | ---- |
+| contact_list | 当前用户的微信联系人列表 |
+| group_list | 当前用户的微信群列表 |
+| session | WXBot与WEB微信服务器端交互所用的requests Session对象 |
+
+WXBot对象还含有一些可以利用的方法:
+
+| 方法 | 描述 |
+| ---- | --- |
+| get_icon(id) | 获取用户icon并保存到本地文件 img_[id].jpg ,id为用户id(Web微信数据) |
+| 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_user_remark_name(uid) | 获取好友的备注名,没有备注名则获取好友微信号, uid为好友的用户id(Web微信数据) |
+| send_msg_by_uid(word, dst) | 向好友发送消息,word为消息字符串,dst为好友用户id(Web微信数据) |
+| send_msg(name, word, isfile) | 向好友发送消息,name为好友的备注名或者好友微信号,isfile为False时word为消息,isfile为True时word为文件路径(此时向好友发送文件里的每一行) |

BIN
img/backfront.jpg


BIN
img/login_on_ubuntu.png


BIN
img/send_msg.png


+ 24 - 0
test.py

@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+# coding: utf-8
+
+import time
+from wxbot import *
+
+class MyWXBot(WXBot):
+    def handle_msg_all(self, msg):
+        if msg['msg_type_id'] == 5 and msg['user_type'] == 'contact':
+            self.send_msg_by_uid('hi', msg['user_id'])
+'''
+    def schedule(self):
+        self.send_msg('tb', 'schedule')
+        time.sleep(1)
+'''
+
+def main():
+    bot = MyWXBot()
+    bot.DEBUG = True
+    bot.conf['qr'] = 'png'
+    bot.run()
+
+if __name__ == '__main__':
+    main()

+ 250 - 202
wxbot.py

@@ -32,27 +32,21 @@ class WXBot:
         self.sid = ''
         self.skey = ''
         self.pass_ticket = ''
-        self.deviceId = 'e' + repr(random.random())[2:17]
-        self.BaseRequest = {}
-        self.synckey = ''
-        self.SyncKey = []
-        self.User = []
-        self.MemberList = []
-        self.ContactList = []
-        self.GroupList = []
-        self.is_auto_reply = False
-        self.syncHost = ''
+        self.device_id = 'e' + repr(random.random())[2:17]
+        self.base_request = {}
+        self.sync_key_str = ''
+        self.sync_key = []
+        self.user = []
+        self.member_list = []
+        self.contact_list = []  # contact list
+        self.public_list = []   # public account list
+        self.group_list = []    # group chat list
+        self.special_list = []  # special list account
+        self.sync_host = ''
         self.session = requests.Session()
         self.session.headers.update({'User-Agent': 'Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5'})
 
-        try:
-            with open('auto.json') as f:
-                cfg = json.load(f)
-                self.auto_reply_url = cfg['url']
-                self.auto_reply_key = cfg['key']
-        except Exception, e:
-            self.auto_reply_url = None
-            self.auto_reply_key = None
+        self.conf = {'qr': 'png',}
 
     def get_uuid(self):
         url = 'https://login.weixin.qq.com/jslogin'
@@ -73,10 +67,15 @@ class WXBot:
             return code == '200'
         return False
 
-    def gen_qr_code(self):
+    def gen_qr_code(self, qr_file_path):
         string = 'https://login.weixin.qq.com/l/' + self.uuid
         qr = pyqrcode.create(string)
-        qr.png('qr.jpg')
+        if self.conf['qr'] == 'png':
+            qr.png(qr_file_path)
+        elif self.conf['qr'] == 'tty':
+            print 'Not support tty'
+            pass
+            #qr.print_tty()
 
     def wait4login(self, tip):
         time.sleep(tip)
@@ -96,9 +95,9 @@ class WXBot:
             self.base_uri = redirect_uri[:redirect_uri.rfind('/')]
             return True
         elif code == '408':
-            print '[login timeout]'
+            print '[ERROR] WeChat login timeout .'
         else:
-            print '[login exception]'
+            print '[ERROR] WeChat login exception .'
         return False
 
     def login(self):
@@ -121,108 +120,90 @@ class WXBot:
         if '' in (self.skey, self.sid, self.uin, self.pass_ticket):
             return False
 
-        self.BaseRequest = {
+        self.base_request = {
             'Uin': self.uin,
             'Sid': self.sid,
             'Skey': self.skey,
-            'DeviceID': self.deviceId,
+            'DeviceID': self.device_id,
             }
         return True
 
     def init(self):
         url = self.base_uri + '/webwxinit?r=%i&lang=en_US&pass_ticket=%s' % (int(time.time()), self.pass_ticket)
         params = {
-            'BaseRequest': self.BaseRequest
+            'BaseRequest': self.base_request
         }
-        r = self.session.post(url, json=params)
+        r = self.session.post(url, data=json.dumps(params))
         r.encoding = 'utf-8'
         dic = json.loads(r.text)
-        self.SyncKey = dic['SyncKey']
-        self.User = dic['User']
-        self.synckey = '|'.join([ str(keyVal['Key']) + '_' + str(keyVal['Val']) for keyVal in self.SyncKey['List'] ])
+        self.sync_key = dic['SyncKey']
+        self.user = dic['User']
+        self.sync_key_str = '|'.join([ str(keyVal['Key']) + '_' + str(keyVal['Val']) for keyVal in self.sync_key['List'] ])
         return dic['BaseResponse']['Ret'] == 0
 
     def status_notify(self):
         url = self.base_uri + '/webwxstatusnotify?lang=zh_CN&pass_ticket=%s' % (self.pass_ticket)
-        self.BaseRequest['Uin'] = int(self.BaseRequest['Uin'])
+        self.base_request['Uin'] = int(self.base_request['Uin'])
         params = {
-            'BaseRequest': self.BaseRequest,
+            'BaseRequest': self.base_request,
             "Code": 3,
-            "FromUserName": self.User['UserName'],
-            "ToUserName": self.User['UserName'],
+            "FromUserName": self.user['UserName'],
+            "ToUserName": self.user['UserName'],
             "ClientMsgId": int(time.time())
         }
-        r = self.session.post(url, json=params)
+        r = self.session.post(url, data=json.dumps(params))
         r.encoding = 'utf-8'
         dic = json.loads(r.text)
         return dic['BaseResponse']['Ret'] == 0
 
     def get_contact(self):
         url = self.base_uri + '/webwxgetcontact?pass_ticket=%s&skey=%s&r=%s' % (self.pass_ticket, self.skey, int(time.time()))
-        r = self.session.post(url, json={})
+        r = self.session.post(url, data='{}')
         r.encoding = 'utf-8'
         if self.DEBUG:
             with open('contacts.json', 'w') as f:
                 f.write(r.text.encode('utf-8'))
         dic = json.loads(r.text)
-        self.MemberList = dic['MemberList']
-
-        ContactList = self.MemberList[:]
-        SpecialUsers = [
-            'newsapp',
-            'fmessage',
-            'filehelper',
-            'weibo',
-            'qqmail',
-            'fmessage',
-            'tmessage',
-            'qmessage',
-            'qqsync',
-            'floatbottle',
-            'lbsapp',
-            'shakeapp',
-            'medianote',
-            'qqfriend',
-            'readerapp',
-            'blogapp',
-            'facebookapp',
-            'masssendapp',
-            'meishiapp',
-            'feedsapp',
-            'voip',
-            'blogappweixin',
-            'weixin',
-            'brandsessionholder',
-            'weixinreminder',
-            'wxid_novlwrv3lqwv11',
-            'gh_22b87fa7cb3c',
-            'officialaccounts',
-            'notification_messages',
-            'wxid_novlwrv3lqwv11',
-            'gh_22b87fa7cb3c',
-            'wxitil',
-            'userexperience_alarm',
-            'notification_messages']
-        for contact in ContactList:
+        self.member_list = dic['MemberList']
+
+        SpecialUsers = ['newsapp','fmessage','filehelper','weibo','qqmail','fmessage','tmessage','qmessage','qqsync','floatbottle','lbsapp','shakeapp','medianote',
+            'qqfriend','readerapp','blogapp','facebookapp','masssendapp','meishiapp','feedsapp','voip','blogappweixin','weixin','brandsessionholder','weixinreminder','wxid_novlwrv3lqwv11',
+            'gh_22b87fa7cb3c','officialaccounts','notification_messages','wxid_novlwrv3lqwv11','gh_22b87fa7cb3c','wxitil','userexperience_alarm','notification_messages']
+
+        self.contact_list = []
+        self.public_list = []
+        self.special_list = []
+        self.group_list = []
+        for contact in self.member_list:
             if contact['VerifyFlag'] & 8 != 0: # public account
-                ContactList.remove(contact)
+                self.public_list.append(contact)
             elif contact['UserName'] in SpecialUsers: # special account
-                ContactList.remove(contact)
+                self.special_list.append(contact)
             elif contact['UserName'].find('@@') != -1: # group
-                self.GroupList.append(contact)
-                ContactList.remove(contact)
-            elif contact['UserName'] == self.User['UserName']: # self
-                ContactList.remove(contact)
-        self.ContactList = ContactList
+                self.group_list.append(contact)
+            elif contact['UserName'] == self.user['UserName']: # self
+                pass
+            else:
+                self.contact_list.append(contact)
+
+        if self.DEBUG:
+            with open('contact_list.json', 'w') as f:
+                f.write(json.dumps(self.contact_list))
+            with open('special_list.json', 'w') as f:
+                f.write(json.dumps(self.special_list))
+            with open('group_list.json', 'w') as f:
+                f.write(json.dumps(self.group_list))
+            with open('public_list.json', 'w') as f:
+                f.write(json.dumps(self.public_list))
 
         return True
 
     def batch_get_contact(self):
         url = self.base_uri + '/webwxbatchgetcontact?type=ex&r=%s&pass_ticket=%s' % (int(time.time()), self.pass_ticket)
         params = {
-            'BaseRequest': self.BaseRequest,
-            "Count": len(self.GroupList),
-            "List": [ {"UserName": g['UserName'], "EncryChatRoomId":""} for g in self.GroupList ]
+            'BaseRequest': self.base_request,
+            "Count": len(self.group_list),
+            "List": [ {"UserName": g['UserName'], "EncryChatRoomId":""} for g in self.group_list ]
         }
         r = self.session.post(url, data=params)
         r.encoding = 'utf-8'
@@ -231,7 +212,7 @@ class WXBot:
 
     def test_sync_check(self):
         for host in ['webpush', 'webpush2']:
-            self.syncHost = host
+            self.sync_host = host
             [retcode, selector] = self.sync_check()
             if retcode == '0':
                 return True
@@ -243,11 +224,11 @@ class WXBot:
             'sid': self.sid,
             'uin': self.uin,
             'skey': self.skey,
-            'deviceid': self.deviceId,
-            'synckey': self.synckey,
+            'deviceid': self.device_id,
+            'synckey': self.sync_key_str,
             '_': int(time.time()),
         }
-        url = 'https://' + self.syncHost + '.weixin.qq.com/cgi-bin/mmwebwx-bin/synccheck?' + urllib.urlencode(params)
+        url = 'https://' + self.sync_host + '.weixin.qq.com/cgi-bin/mmwebwx-bin/synccheck?' + urllib.urlencode(params)
         r = self.session.get(url)
         r.encoding = 'utf-8'
         data = r.text
@@ -259,18 +240,16 @@ class WXBot:
     def sync(self):
         url = self.base_uri + '/webwxsync?sid=%s&skey=%s&lang=en_US&pass_ticket=%s' % (self.sid, self.skey, self.pass_ticket)
         params = {
-            'BaseRequest': self.BaseRequest,
-            'SyncKey': self.SyncKey,
+            'BaseRequest': self.base_request,
+            'SyncKey': self.sync_key,
             'rr': ~int(time.time())
         }
-        r = self.session.post(url, json=params)
+        r = self.session.post(url, data=json.dumps(params))
         r.encoding = 'utf-8'
         dic = json.loads(r.text)
-        if self.DEBUG:
-            print json.dumps(dic, indent=4)
         if dic['BaseResponse']['Ret'] == 0:
-            self.SyncKey = dic['SyncKey']
-            self.synckey = '|'.join([ str(keyVal['Key']) + '_' + str(keyVal['Val']) for keyVal in self.SyncKey['List'] ])
+            self.sync_key = dic['SyncKey']
+            self.sync_key_str = '|'.join([ str(keyVal['Key']) + '_' + str(keyVal['Val']) for keyVal in self.sync_key['List'] ])
         return dic
 
     def get_icon(self, id):
@@ -291,6 +270,9 @@ class WXBot:
             f.write(data)
         return fn
 
+    def get_msg_img_url(self, msgid):
+        return self.base_uri + '/webwxgetmsgimg?MsgID=%s&skey=%s' % (msgid, self.skey)
+
     def get_msg_img(self, msgid):
         url = self.base_uri + '/webwxgetmsgimg?MsgID=%s&skey=%s' % (msgid, self.skey)
         r = self.session.get(url)
@@ -300,15 +282,8 @@ class WXBot:
             f.write(data)
         return fn
 
-    # Not work now for weixin haven't support this API
-    def get_video(self, msgid):
-        url = self.base_uri + '/webwxgetvideo?msgid=%s&skey=%s' % (msgid, self.skey)
-        r = self.session.get(url)
-        data = r.content
-        fn = 'video_'+msgid+'.mp4'
-        with open(fn, 'wb') as f:
-            f.write(data)
-        return fn
+    def get_voice_url(self, msgid):
+        return self.base_uri + '/webwxgetvoice?msgid=%s&skey=%s' % (msgid, self.skey)
 
     def get_voice(self, msgid):
         url = self.base_uri + '/webwxgetvoice?msgid=%s&skey=%s' % (msgid, self.skey)
@@ -322,130 +297,218 @@ class WXBot:
     #Get the NickName or RemarkName of an user by user id
     def get_user_remark_name(self, uid):
         name = 'unknown group' if uid[:2] == '@@' else 'stranger'
-        for member in self.MemberList:
+        for member in self.member_list:
             if member['UserName'] == uid:
                 name = member['RemarkName'] if member['RemarkName'] else member['NickName']
         return name
 
     #Get user id of an user
     def get_user_id(self, name):
-        for member in self.MemberList:
+        for member in self.member_list:
             if name == member['RemarkName'] or name == member['NickName'] or name == member['UserName']:
                 return member['UserName']
         return None
 
-    def auto_reply(self, word):
-        if self.auto_reply_key == None or self.auto_reply_url == None:
-            return 'hi'
-
-        body = {'key': self.auto_reply_key, 'info':word}
-        r = requests.post(self.auto_reply_url, data=body)
-        resp = json.loads(r.text)
-        if resp['code'] == 100000:
-            return resp['text']
-        else:
-            return None
+    def get_user_type(self, wx_user_id):
+        for account in self.contact_list:
+            if wx_user_id == account['UserName']:
+                return 'contact'
+        for account in self.public_list:
+            if wx_user_id == account['UserName']:
+                return 'public'
+        for account in self.special_list:
+            if wx_user_id == account['UserName']:
+                return 'special'
+        for account in self.group_list:
+            if wx_user_id == account['UserName']:
+                return 'group'
+        return 'unknown'
 
+    '''
+    msg:
+        user_type
+        msg_id
+        msg_type_id
+        user_id
+        user_name
+        content
+    '''
+    def handle_msg_all(self, msg):
+        pass
+
+    '''
+    msg_type_id:
+        1 -> Location
+        2 -> FileHelper
+        3 -> Self
+        4 -> Group
+        5 -> User Text Message
+        6 -> Image
+        7 -> Voice
+        8 -> Recommend
+        9 -> Animation
+        10 -> Share
+        11 -> Video
+        12 -> Video Call
+        13 -> Redraw
+        14 -> Init Message
+        99 -> Unknown
+    '''
     def handle_msg(self, r):
         for msg in r['AddMsgList']:
-            msgType = msg['MsgType']
-            name = self.get_user_remark_name(msg['FromUserName']) #FromUserName is user id
+            mtype = msg['MsgType']
+
+            wx_user_id = msg['FromUserName']
+            user_type = self.get_user_type(wx_user_id)
+
+            name = self.get_user_remark_name(wx_user_id)
             content = msg['Content'].replace('&lt;','<').replace('&gt;','>')
-            msgid = msg['MsgId']
-            if msgType == 51: #init message
-                pass
-            elif msgType == 1:
+            msg_id = msg['MsgId']
+            msg_type_id = 99
+
+
+            if mtype == 51: #init message
+                msg_type_id = 14
+            elif mtype == 1:
                 if content.find('http://weixin.qq.com/cgi-bin/redirectforward?args=') != -1:
                     r = self.session.get(content)
                     r.encoding = 'gbk'
                     data = r.text
                     pos = self.search_content('title', data, 'xml')
-                    print '[Location] %s : I am at %s ' % (name, pos)
+                    msg_type_id = 1
+                    content = {'location': pos, 'xml': data}
+                    if self.DEBUG:
+                        print '[Location] %s : I am at %s ' % (name, pos)
+
                 elif msg['ToUserName'] == 'filehelper':
-                    print '[File] %s : %s' % (name, content.replace('<br/>','\n'))
-                elif msg['FromUserName'] == self.User['UserName']: #self
-                    pass
+                    msg_type_id = 2
+                    content = content.replace('<br/>','\n')
+                    if self.DEBUG:
+                        print '[File] %s : %s' % (name, )
+
+                elif msg['FromUserName'] == self.user['UserName']: #self
+                    msg_type_id = 3
+
                 elif msg['FromUserName'][:2] == '@@':
                     [people, content] = content.split(':<br/>')
                     group = self.get_user_remark_name(msg['FromUserName'])
                     name = self.get_user_remark_name(people)
-                    print '[Group] |%s| %s: %s' % (group, name, content.replace('<br/>','\n'))
+                    msg_type_id = 4
+                    content = {'group_id': msg['FromUserName'], 'group_name': group, 'user': people, 'user_name': name, 'msg': content}
+                    if self.DEBUG:
+                        print '[Group] |%s| %s: %s' % (group, name, content.replace('<br/>','\n'))
+
                 else:
-                    print '[Text] ', name, ' : ', content
-                    if self.is_auto_reply:
-                        ans = self.auto_reply(content)
-                        if ans:
-                            if self.send_msg(msg['FromUserName'], ans):
-                                print '[AUTO] Me : ', ans
-                            else:
-                                print '[AUTO] Failed'
-            elif msgType == 3:
-                image = self.get_msg_img(msgid)
-                print '[Image] %s : %s' % (name, image)
-            elif msgType == 34:
-                voice = self.get_voice(msgid)
-                print '[Voice] %s : %s' % (name, voice)
-            elif msgType == 42:
+                    msg_type_id = 5
+                    if self.DEBUG:
+                        print '[Text] ', name, ' : ', content
+
+            elif mtype == 3:
+                msg_type_id = 6
+                content = self.get_msg_img_url(msg_id)
+                if self.DEBUG:
+                    image = self.get_msg_img(msg_id)
+                    print '[Image] %s : %s' % (name, image)
+
+            elif mtype == 34:
+                msg_type_id = 7
+                content = self.get_voice_url(msg_id)
+                if self.DEBUG:
+                    voice = self.get_voice(msg_id)
+                    print '[Voice] %s : %s' % (name, voice)
+
+            elif mtype == 42:
+                msg_type_id = 8
+
                 info = msg['RecommendInfo']
-                print '[Recommend] %s : ' % name
-                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 msgType == 47:
+                content = {}
+                content['nickname'] = info['NickName']
+                content['alias'] = info['Alias']
+                content['province'] = info['Province']
+                content['city'] = info['City']
+                content['gender'] = ['unknown', 'male', 'female'][info['Sex']]
+                if self.DEBUG:
+                    print '[Recommend] %s : ' % name
+                    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_type_id = 9
                 url = self.search_content('cdnurl', content)
-                print '[Animation] %s : %s' % (name, url)
-            elif msgType == 49:
+                content = url
+                if self.DEBUG:
+                    print '[Animation] %s : %s' % (name, url)
+
+            elif mtype == 49:
+                msg_type_id = 10
                 appMsgType = defaultdict(lambda : "")
                 appMsgType.update({5:'link', 3:'music', 7:'weibo'})
-                print '[Share] %s : %s' % (name, appMsgType[msg['AppMsgType']])
-                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 '========================='
-            elif msgType == 62:
-                print '[Video] ', name, ' sent you a video, please check on mobiles'
-            elif msgType == 53:
-                print '[Video Call] ', name, ' call you'
-            elif msgType == 10002:
-                print '[Redraw] ', name, ' redraw back a message'
+                content = {'type': appMsgType[msg['AppMsgType']], 'title': msg['FileName'], 'desc': self.search_content('des', content, 'xml'), 'url': msg['Url'], 'from': self.search_content('appname', content, 'xml')}
+                if self.DEBUG:
+                    print '[Share] %s : %s' % (name, appMsgType[msg['AppMsgType']])
+                    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 '========================='
+
+            elif mtype == 62:
+                msg_type_id = 11
+                if self.DEBUG:
+                    print '[Video] ', name, ' sent you a video, please check on mobiles'
+
+            elif mtype == 53:
+                msg_type_id = 12
+                if self.DEBUG:
+                    print '[Video Call] ', name, ' call you'
+            elif mtype == 10002:
+                msg_type_id = 13
+                if self.DEBUG:
+                    print '[Redraw] ', name, ' redraw back a message'
             else:
-                print '[Maybe] : %s,maybe image or link' % str(msg['MsgType'])
-                print msg
+                msg_type_id = 99
+                if self.DEBUG:
+                    print '[Unknown] : %s' % str(mtype)
+                    print msg
+            message = {'user_type': user_type, 'msg_id':msg_id, 'msg_type_id': msg_type_id, 'content': content, 'user_id': msg['FromUserName'], 'user_name': name}
+            self.handle_msg_all(message)
+
+    def schedule(self):
+        pass
 
     def proc_msg(self):
-        print 'proc start'
         self.test_sync_check()
         while True:
             [retcode, selector] = self.sync_check()
-            if retcode == '1100':
+            if retcode == '1100': # User have login on mobile
                 pass
-                #print '[*] you have login on mobile'
             elif retcode == '0':
                 if selector == '2':
                     r = self.sync()
                     if r is not None:
                         self.handle_msg(r)
-                elif selector == '7': # play WeChat on mobile
+                elif selector == '7': # Play WeChat on mobile
                     r = self.sync()
                     if r is not None:
                         self.handle_msg(r)
                 elif selector == '0':
                     time.sleep(1)
+            self.schedule()
 
     def send_msg_by_uid(self, word, dst = 'filehelper'):
         url = self.base_uri + '/webwxsendmsg?pass_ticket=%s' % (self.pass_ticket)
         msg_id = str(int(time.time()*1000)) + str(random.random())[:5].replace('.','')
         params = {
-            'BaseRequest': self.BaseRequest,
+            'BaseRequest': self.base_request,
             'Msg': {
                 "Type": 1,
                 "Content": make_unicode(word),
-                "FromUserName": self.User['UserName'],
+                "FromUserName": self.user['UserName'],
                 "ToUserName": dst,
                 "LocalID": msg_id,
                 "ClientMsgId": msg_id
@@ -478,8 +541,10 @@ class WXBot:
                 else:
                     return False
         else:
-            print '[*] this user does not exist'
-            return False
+            if self.DEBUG:
+                print '[ERROR] This user does not exist .'
+            return True
+
     def search_content(self, key, content, fmat = 'attr'):
         if fmat == 'attr':
             pm = re.search(key+'\s?=\s?"([^"<]+)"', content)
@@ -491,40 +556,23 @@ class WXBot:
 
     def run(self):
         self.get_uuid()
-        print 'get uuid end'
-        self.gen_qr_code()
-        print 'gen qr code end'
+        self.gen_qr_code('qr.png')
+        print '[INFO] Please use WeCaht to scan the QR code .'
         self.wait4login(1)
-        print 'wait4login end'
+        print '[INFO] Please confirm to login .'
         self.wait4login(0)
-        print 'wait4login end'
         if self.login():
-            print 'login succeed'
+            print '[INFO] Web WeChat login succeed .'
         else:
-            print 'login failed'
+            print '[ERROR] Web WeChat login failed .'
             return
         if self.init():
-            print 'init succeed'
+            print '[INFO] Web WeChat init succeed .'
         else:
-            print 'init failed'
+            print '[INFO] Web WeChat init failed'
             return
-        print 'init end'
         self.status_notify()
-        print 'status notify end'
         self.get_contact()
-        print 'get %d contacts' % len(self.ContactList)
-
-        if raw_input('auto reply?(y/n): ') == 'y':
-            self.is_auto_reply = True
-            print 'auto reply opened'
-        else:
-            print 'auto reply closed'
-
+        print '[INFO] Get %d contacts' % len(self.contact_list)
+        print '[INFO] Start to process messages .'
         self.proc_msg()
-
-def main():
-    bot = WXBot()
-    bot.run()
-
-if __name__ == '__main__':
-    main()