wxbot.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. #!/usr/bin/env python
  2. # coding: utf-8
  3. import pyqrcode
  4. import requests
  5. import json
  6. import xml.dom.minidom
  7. import urllib
  8. import time
  9. import re
  10. import random
  11. def utf82gbk(string):
  12. return string.decode('utf8').encode('gbk')
  13. def make_unicode(data):
  14. if not data:
  15. return data
  16. result = None
  17. if type(data) == unicode:
  18. result = data
  19. elif type(data) == str:
  20. result = data.decode('utf-8')
  21. return result
  22. class WXBot:
  23. def __init__(self):
  24. self.DEBUG = False
  25. self.uuid = ''
  26. self.base_uri = ''
  27. self.redirect_uri = ''
  28. self.uin = ''
  29. self.sid = ''
  30. self.skey = ''
  31. self.pass_ticket = ''
  32. self.device_id = 'e' + repr(random.random())[2:17]
  33. self.base_request = {}
  34. self.sync_key_str = ''
  35. self.sync_key = []
  36. self.user = {}
  37. self.member_list = []
  38. self.contact_list = [] # contact list
  39. self.public_list = [] # public account list
  40. self.group_list = [] # group chat list
  41. self.special_list = [] # special list account
  42. self.sync_host = ''
  43. self.session = requests.Session()
  44. self.session.headers.update({'User-Agent': 'Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5'})
  45. self.conf = {'qr': 'png'}
  46. def get_uuid(self):
  47. url = 'https://login.weixin.qq.com/jslogin'
  48. params = {
  49. 'appid': 'wx782c26e4c19acffb',
  50. 'fun': 'new',
  51. 'lang': 'zh_CN',
  52. '_': int(time.time())*1000 + random.randint(1, 999),
  53. }
  54. r = self.session.get(url, params=params)
  55. r.encoding = 'utf-8'
  56. data = r.text
  57. regx = r'window.QRLogin.code = (\d+); window.QRLogin.uuid = "(\S+?)"'
  58. pm = re.search(regx, data)
  59. if pm:
  60. code = pm.group(1)
  61. self.uuid = pm.group(2)
  62. return code == '200'
  63. return False
  64. def gen_qr_code(self, qr_file_path):
  65. string = 'https://login.weixin.qq.com/l/' + self.uuid
  66. qr = pyqrcode.create(string)
  67. if self.conf['qr'] == 'png':
  68. qr.png(qr_file_path)
  69. elif self.conf['qr'] == 'tty':
  70. print(qr.terminal(quiet_zone=1))
  71. def wait4login(self, tip):
  72. time.sleep(tip)
  73. url = 'https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login?tip=%s&uuid=%s&_=%s' \
  74. % (tip, self.uuid, int(time.time()))
  75. r = self.session.get(url)
  76. r.encoding = 'utf-8'
  77. data = r.text
  78. param = re.search(r'window.code=(\d+);', data)
  79. code = param.group(1)
  80. if code == '201':
  81. return True
  82. elif code == '200':
  83. param = re.search(r'window.redirect_uri="(\S+?)";', data)
  84. redirect_uri = param.group(1) + '&fun=new'
  85. self.redirect_uri = redirect_uri
  86. self.base_uri = redirect_uri[:redirect_uri.rfind('/')]
  87. return True
  88. elif code == '408':
  89. print '[ERROR] WeChat login timeout .'
  90. else:
  91. print '[ERROR] WeChat login exception .'
  92. return False
  93. def login(self):
  94. r = self.session.get(self.redirect_uri)
  95. r.encoding = 'utf-8'
  96. data = r.text
  97. doc = xml.dom.minidom.parseString(data)
  98. root = doc.documentElement
  99. for node in root.childNodes:
  100. if node.nodeName == 'skey':
  101. self.skey = node.childNodes[0].data
  102. elif node.nodeName == 'wxsid':
  103. self.sid = node.childNodes[0].data
  104. elif node.nodeName == 'wxuin':
  105. self.uin = node.childNodes[0].data
  106. elif node.nodeName == 'pass_ticket':
  107. self.pass_ticket = node.childNodes[0].data
  108. if '' in (self.skey, self.sid, self.uin, self.pass_ticket):
  109. return False
  110. self.base_request = {
  111. 'Uin': self.uin,
  112. 'Sid': self.sid,
  113. 'Skey': self.skey,
  114. 'DeviceID': self.device_id,
  115. }
  116. return True
  117. def init(self):
  118. url = self.base_uri + '/webwxinit?r=%i&lang=en_US&pass_ticket=%s' % (int(time.time()), self.pass_ticket)
  119. params = {
  120. 'BaseRequest': self.base_request
  121. }
  122. r = self.session.post(url, data=json.dumps(params))
  123. r.encoding = 'utf-8'
  124. dic = json.loads(r.text)
  125. self.sync_key = dic['SyncKey']
  126. self.user = dic['User']
  127. self.sync_key_str = '|'.join([str(keyVal['Key']) + '_' + str(keyVal['Val'])
  128. for keyVal in self.sync_key['List']])
  129. return dic['BaseResponse']['Ret'] == 0
  130. def status_notify(self):
  131. url = self.base_uri + '/webwxstatusnotify?lang=zh_CN&pass_ticket=%s' % self.pass_ticket
  132. self.base_request['Uin'] = int(self.base_request['Uin'])
  133. params = {
  134. 'BaseRequest': self.base_request,
  135. "Code": 3,
  136. "FromUserName": self.user['UserName'],
  137. "ToUserName": self.user['UserName'],
  138. "ClientMsgId": int(time.time())
  139. }
  140. r = self.session.post(url, data=json.dumps(params))
  141. r.encoding = 'utf-8'
  142. dic = json.loads(r.text)
  143. return dic['BaseResponse']['Ret'] == 0
  144. def get_contact(self):
  145. url = self.base_uri + '/webwxgetcontact?pass_ticket=%s&skey=%s&r=%s' \
  146. % (self.pass_ticket, self.skey, int(time.time()))
  147. r = self.session.post(url, data='{}')
  148. r.encoding = 'utf-8'
  149. if self.DEBUG:
  150. with open('contacts.json', 'w') as f:
  151. f.write(r.text.encode('utf-8'))
  152. dic = json.loads(r.text)
  153. self.member_list = dic['MemberList']
  154. special_users = ['newsapp', 'fmessage', 'filehelper', 'weibo', 'qqmail',
  155. 'fmessage', 'tmessage', 'qmessage', 'qqsync', 'floatbottle',
  156. 'lbsapp', 'shakeapp', 'medianote', 'qqfriend', 'readerapp',
  157. 'blogapp', 'facebookapp', 'masssendapp', 'meishiapp',
  158. 'feedsapp', 'voip', 'blogappweixin', 'weixin', 'brandsessionholder',
  159. 'weixinreminder', 'wxid_novlwrv3lqwv11', 'gh_22b87fa7cb3c',
  160. 'officialaccounts', 'notification_messages', 'wxid_novlwrv3lqwv11',
  161. 'gh_22b87fa7cb3c', 'wxitil', 'userexperience_alarm', 'notification_messages']
  162. self.contact_list = []
  163. self.public_list = []
  164. self.special_list = []
  165. self.group_list = []
  166. for contact in self.member_list:
  167. if contact['VerifyFlag'] & 8 != 0: # public account
  168. self.public_list.append(contact)
  169. elif contact['UserName'] in special_users: # special account
  170. self.special_list.append(contact)
  171. elif contact['UserName'].find('@@') != -1: # group
  172. self.group_list.append(contact)
  173. elif contact['UserName'] == self.user['UserName']: # self
  174. pass
  175. else:
  176. self.contact_list.append(contact)
  177. if self.DEBUG:
  178. with open('contact_list.json', 'w') as f:
  179. f.write(json.dumps(self.contact_list))
  180. with open('special_list.json', 'w') as f:
  181. f.write(json.dumps(self.special_list))
  182. with open('group_list.json', 'w') as f:
  183. f.write(json.dumps(self.group_list))
  184. with open('public_list.json', 'w') as f:
  185. f.write(json.dumps(self.public_list))
  186. with open('member_list.json', 'w') as f:
  187. f.write(json.dumps(self.member_list))
  188. return True
  189. def batch_get_contact(self):
  190. url = self.base_uri + '/webwxbatchgetcontact?type=ex&r=%s&pass_ticket=%s' % (int(time.time()), self.pass_ticket)
  191. params = {
  192. 'BaseRequest': self.base_request,
  193. "Count": len(self.group_list),
  194. "List": [{"UserName": g['UserName'], "EncryChatRoomId":""} for g in self.group_list]
  195. }
  196. r = self.session.post(url, data=params)
  197. r.encoding = 'utf-8'
  198. dic = json.loads(r.text)
  199. return dic
  200. def test_sync_check(self):
  201. for host in ['webpush', 'webpush2']:
  202. self.sync_host = host
  203. retcode = self.sync_check()[0]
  204. if retcode == '0':
  205. return True
  206. return False
  207. def sync_check(self):
  208. params = {
  209. 'r': int(time.time()),
  210. 'sid': self.sid,
  211. 'uin': self.uin,
  212. 'skey': self.skey,
  213. 'deviceid': self.device_id,
  214. 'synckey': self.sync_key_str,
  215. '_': int(time.time()),
  216. }
  217. url = 'https://' + self.sync_host + '.weixin.qq.com/cgi-bin/mmwebwx-bin/synccheck?' + urllib.urlencode(params)
  218. r = self.session.get(url)
  219. r.encoding = 'utf-8'
  220. data = r.text
  221. pm = re.search(r'window.synccheck=\{retcode:"(\d+)",selector:"(\d+)"\}', data)
  222. retcode = pm.group(1)
  223. selector = pm.group(2)
  224. return [retcode, selector]
  225. def sync(self):
  226. url = self.base_uri + '/webwxsync?sid=%s&skey=%s&lang=en_US&pass_ticket=%s' \
  227. % (self.sid, self.skey, self.pass_ticket)
  228. params = {
  229. 'BaseRequest': self.base_request,
  230. 'SyncKey': self.sync_key,
  231. 'rr': ~int(time.time())
  232. }
  233. r = self.session.post(url, data=json.dumps(params))
  234. r.encoding = 'utf-8'
  235. dic = json.loads(r.text)
  236. if dic['BaseResponse']['Ret'] == 0:
  237. self.sync_key = dic['SyncKey']
  238. self.sync_key_str = '|'.join([str(keyVal['Key']) + '_' + str(keyVal['Val'])
  239. for keyVal in self.sync_key['List']])
  240. return dic
  241. def get_icon(self, uid):
  242. url = self.base_uri + '/webwxgeticon?username=%s&skey=%s' % (uid, self.skey)
  243. r = self.session.get(url)
  244. data = r.content
  245. fn = 'img_'+uid+'.jpg'
  246. with open(fn, 'wb') as f:
  247. f.write(data)
  248. return fn
  249. def get_head_img(self, uid):
  250. url = self.base_uri + '/webwxgetheadimg?username=%s&skey=%s' % (uid, self.skey)
  251. r = self.session.get(url)
  252. data = r.content
  253. fn = 'img_'+uid+'.jpg'
  254. with open(fn, 'wb') as f:
  255. f.write(data)
  256. return fn
  257. def get_msg_img_url(self, msgid):
  258. return self.base_uri + '/webwxgetmsgimg?MsgID=%s&skey=%s' % (msgid, self.skey)
  259. def get_msg_img(self, msgid):
  260. url = self.base_uri + '/webwxgetmsgimg?MsgID=%s&skey=%s' % (msgid, self.skey)
  261. r = self.session.get(url)
  262. data = r.content
  263. fn = 'img_'+msgid+'.jpg'
  264. with open(fn, 'wb') as f:
  265. f.write(data)
  266. return fn
  267. def get_voice_url(self, msgid):
  268. return self.base_uri + '/webwxgetvoice?msgid=%s&skey=%s' % (msgid, self.skey)
  269. def get_voice(self, msgid):
  270. url = self.base_uri + '/webwxgetvoice?msgid=%s&skey=%s' % (msgid, self.skey)
  271. r = self.session.get(url)
  272. data = r.content
  273. fn = 'voice_'+msgid+'.mp3'
  274. with open(fn, 'wb') as f:
  275. f.write(data)
  276. return fn
  277. # Get the NickName or RemarkName of an user by user id
  278. def get_user_remark_name(self, uid):
  279. name = 'unknown group' if uid[:2] == '@@' else 'stranger'
  280. for member in self.member_list:
  281. if member['UserName'] == uid:
  282. name = member['RemarkName'] if member['RemarkName'] else member['NickName']
  283. return name
  284. # Get user id of an user
  285. def get_user_id(self, name):
  286. for member in self.member_list:
  287. if name == member['RemarkName'] or name == member['NickName'] or name == member['UserName']:
  288. return member['UserName']
  289. return None
  290. def get_user_type(self, wx_user_id):
  291. for account in self.contact_list:
  292. if wx_user_id == account['UserName']:
  293. return 'contact'
  294. for account in self.public_list:
  295. if wx_user_id == account['UserName']:
  296. return 'public'
  297. for account in self.special_list:
  298. if wx_user_id == account['UserName']:
  299. return 'special'
  300. for account in self.group_list:
  301. if wx_user_id == account['UserName']:
  302. return 'group'
  303. return 'unknown'
  304. def is_contact(self, uid):
  305. for account in self.contact_list:
  306. if uid == account['UserName']:
  307. return True
  308. return False
  309. def is_public(self, uid):
  310. for account in self.public_list:
  311. if uid == account['UserName']:
  312. return True
  313. return False
  314. def is_special(self, uid):
  315. for account in self.special_list:
  316. if uid == account['UserName']:
  317. return True
  318. return False
  319. '''
  320. msg:
  321. user
  322. type
  323. data
  324. detail
  325. '''
  326. def handle_msg_all(self, msg):
  327. pass
  328. '''
  329. content_type_id:
  330. 0 -> Text
  331. 1 -> Location
  332. 3 -> Image
  333. 4 -> Voice
  334. 5 -> Recommend
  335. 6 -> Animation
  336. 7 -> Share
  337. 8 -> Video
  338. 9 -> VideoCall
  339. 10 -> Redraw
  340. 11 -> Empty
  341. 99 -> Unknown
  342. '''
  343. def extract_msg_content(self, msg_type_id, msg):
  344. mtype = msg['MsgType']
  345. content = msg['Content'].replace('&lt;', '<').replace('&gt;', '>')
  346. msg_id = msg['MsgId']
  347. msg_content = {}
  348. if msg_type_id == 0:
  349. return {'type': 11, 'data': ''}
  350. elif msg_type_id == 2: # File Helper
  351. return {'type': 0, 'data': content.replace('<br/>', '\n')}
  352. elif msg_type_id == 3: # Group
  353. sp = content.find('<br/>')
  354. uid = content[:sp]
  355. content = content[sp:]
  356. content = content.replace('<br/>', '')
  357. uid = uid[:-1]
  358. msg_content['user'] = {'id': uid, 'name': self.get_user_remark_name(uid)}
  359. if self.DEBUG:
  360. print msg_content['user']
  361. else: # Self, Contact, Special, Public, Unknown
  362. pass
  363. if mtype == 1:
  364. if content.find('http://weixin.qq.com/cgi-bin/redirectforward?args=') != -1:
  365. r = self.session.get(content)
  366. r.encoding = 'gbk'
  367. data = r.text
  368. pos = self.search_content('title', data, 'xml')
  369. msg_content['type'] = 1
  370. msg_content['data'] = pos
  371. msg_content['detail'] = data
  372. if self.DEBUG:
  373. print '[Location] I am at %s ' % pos
  374. else:
  375. msg_content['type'] = 0
  376. msg_content['data'] = content
  377. if self.DEBUG:
  378. print '[Text] %s' % content
  379. elif mtype == 3:
  380. msg_content['type'] = 3
  381. msg_content['data'] = self.get_msg_img_url(msg_id)
  382. if self.DEBUG:
  383. image = self.get_msg_img(msg_id)
  384. print '[Image] %s' % image
  385. elif mtype == 34:
  386. msg_content['type'] = 4
  387. msg_content['data'] = self.get_voice_url(msg_id)
  388. if self.DEBUG:
  389. voice = self.get_voice(msg_id)
  390. print '[Voice] %s' % voice
  391. elif mtype == 42:
  392. msg_content['type'] = 5
  393. info = msg['RecommendInfo']
  394. msg_content['data'] = {'nickname': info['NickName'],
  395. 'alias': info['Alias'],
  396. 'province': info['Province'],
  397. 'city': info['City'],
  398. 'gender': ['unknown', 'male', 'female'][info['Sex']]}
  399. if self.DEBUG:
  400. print '[Recommend]'
  401. print '========================='
  402. print '= NickName: %s' % info['NickName']
  403. print '= Alias: %s' % info['Alias']
  404. print '= Local: %s %s' % (info['Province'], info['City'])
  405. print '= Gender: %s' % ['unknown', 'male', 'female'][info['Sex']]
  406. print '========================='
  407. elif mtype == 47:
  408. msg_content['type'] = 6
  409. msg_content['data'] = self.search_content('cdnurl', content)
  410. if self.DEBUG:
  411. print '[Animation] %s' % msg_content['data']
  412. elif mtype == 49:
  413. msg_content['type'] = 7
  414. app_msg_type = ''
  415. if msg['AppMsgType'] == 3:
  416. app_msg_type = 'music'
  417. elif msg['AppMsgType'] == 5:
  418. app_msg_type = 'link'
  419. elif msg['AppMsgType'] == 7:
  420. app_msg_type = 'weibo'
  421. else:
  422. app_msg_type = 'unknown'
  423. msg_content['data'] = {'type': app_msg_type,
  424. 'title': msg['FileName'],
  425. 'desc': self.search_content('des', content, 'xml'),
  426. 'url': msg['Url'],
  427. 'from': self.search_content('appname', content, 'xml')}
  428. if self.DEBUG:
  429. print '[Share] %s' % app_msg_type
  430. print '========================='
  431. print '= title: %s' % msg['FileName']
  432. print '= desc: %s' % self.search_content('des', content, 'xml')
  433. print '= link: %s' % msg['Url']
  434. print '= from: %s' % self.search_content('appname', content, 'xml')
  435. print '========================='
  436. elif mtype == 62:
  437. msg_content['type'] = 8
  438. msg_content['data'] = content
  439. if self.DEBUG:
  440. print '[Video] Please check on mobiles'
  441. elif mtype == 53:
  442. msg_content['type'] = 9
  443. msg_content['data'] = content
  444. if self.DEBUG:
  445. print '[Video Call]'
  446. elif mtype == 10002:
  447. msg_content['type'] = 10
  448. msg_content['data'] = content
  449. if self.DEBUG:
  450. print '[Redraw]'
  451. else:
  452. msg_content['type'] = 99
  453. msg_content['data'] = content
  454. if self.DEBUG:
  455. print '[Unknown]'
  456. return msg_content
  457. '''
  458. msg_type_id:
  459. 0 -> Init
  460. 1 -> Self
  461. 2 -> FileHelper
  462. 3 -> Group
  463. 4 -> Contact
  464. 5 -> Public
  465. 6 -> Special
  466. 99 -> Unknown
  467. '''
  468. def handle_msg(self, r):
  469. for msg in r['AddMsgList']:
  470. msg_type_id = 99
  471. user = {'id': msg['FromUserName']}
  472. if msg['MsgType'] == 51: # init message
  473. msg_type_id = 0
  474. elif msg['FromUserName'] == self.user['UserName']: # Self
  475. msg_type_id = 1
  476. user['name'] = 'self'
  477. elif msg['ToUserName'] == 'filehelper': # File Helper
  478. msg_type_id = 2
  479. user['name'] = 'file_helper'
  480. elif msg['FromUserName'][:2] == '@@': # Group
  481. msg_type_id = 3
  482. user['name'] = self.get_user_remark_name(user['id'])
  483. if self.DEBUG:
  484. print '[From] %s' % user['name']
  485. elif self.is_contact(msg['FromUserName']): # Contact
  486. msg_type_id = 4
  487. user['name'] = self.get_user_remark_name(user['id'])
  488. elif self.is_public(msg['FromUserName']): # Public
  489. msg_type_id = 5
  490. user['name'] = self.get_user_remark_name(user['id'])
  491. elif self.is_special(msg['FromUserName']): # Special
  492. msg_type_id = 6
  493. user['name'] = self.get_user_remark_name(user['id'])
  494. else:
  495. pass # Unknown
  496. content = self.extract_msg_content(msg_type_id, msg)
  497. message = {'msg_type_id': msg_type_id,
  498. 'msg_id': msg['MsgId'],
  499. 'content': content,
  500. 'user': user}
  501. self.handle_msg_all(message)
  502. def schedule(self):
  503. pass
  504. def proc_msg(self):
  505. self.test_sync_check()
  506. while True:
  507. [retcode, selector] = self.sync_check()
  508. if retcode == '1100': # User have login on mobile
  509. pass
  510. elif retcode == '0':
  511. if selector == '2':
  512. r = self.sync()
  513. if r is not None:
  514. self.handle_msg(r)
  515. elif selector == '7': # Play WeChat on mobile
  516. r = self.sync()
  517. if r is not None:
  518. self.handle_msg(r)
  519. elif selector == '0':
  520. time.sleep(1)
  521. self.schedule()
  522. def send_msg_by_uid(self, word, dst='filehelper'):
  523. url = self.base_uri + '/webwxsendmsg?pass_ticket=%s' % self.pass_ticket
  524. msg_id = str(int(time.time()*1000)) + str(random.random())[:5].replace('.', '')
  525. params = {
  526. 'BaseRequest': self.base_request,
  527. 'Msg': {
  528. "Type": 1,
  529. "Content": make_unicode(word),
  530. "FromUserName": self.user['UserName'],
  531. "ToUserName": dst,
  532. "LocalID": msg_id,
  533. "ClientMsgId": msg_id
  534. }
  535. }
  536. headers = {'content-type': 'application/json; charset=UTF-8'}
  537. data = json.dumps(params, ensure_ascii=False).encode('utf8')
  538. r = self.session.post(url, data=data, headers=headers)
  539. dic = r.json()
  540. return dic['BaseResponse']['Ret'] == 0
  541. def send_msg(self, name, word, isfile=False):
  542. uid = self.get_user_id(name)
  543. if uid:
  544. if isfile:
  545. with open(word, 'r') as f:
  546. result = True
  547. for line in f.readlines():
  548. line = line.replace('\n', '')
  549. print '-> '+name+': '+line
  550. if self.send_msg_by_uid(line, uid):
  551. pass
  552. else:
  553. result = False
  554. time.sleep(1)
  555. return result
  556. else:
  557. if self.send_msg_by_uid(word, uid):
  558. return True
  559. else:
  560. return False
  561. else:
  562. if self.DEBUG:
  563. print '[ERROR] This user does not exist .'
  564. return True
  565. def search_content(self, key, content, fmat='attr'):
  566. if fmat == 'attr':
  567. pm = re.search(key+'\s?=\s?"([^"<]+)"', content)
  568. if pm:
  569. return pm.group(1)
  570. elif fmat == 'xml':
  571. pm = re.search('<{0}>([^<]+)</{0}>'.format(key), content)
  572. if pm:
  573. return pm.group(1)
  574. return 'unknown'
  575. def run(self):
  576. self.get_uuid()
  577. self.gen_qr_code('qr.png')
  578. print '[INFO] Please use WeCaht to scan the QR code .'
  579. self.wait4login(1)
  580. print '[INFO] Please confirm to login .'
  581. self.wait4login(0)
  582. if self.login():
  583. print '[INFO] Web WeChat login succeed .'
  584. else:
  585. print '[ERROR] Web WeChat login failed .'
  586. return
  587. if self.init():
  588. print '[INFO] Web WeChat init succeed .'
  589. else:
  590. print '[INFO] Web WeChat init failed'
  591. return
  592. self.status_notify()
  593. self.get_contact()
  594. print '[INFO] Get %d contacts' % len(self.contact_list)
  595. print '[INFO] Start to process messages .'
  596. self.proc_msg()