diff --git a/wxbot.py b/wxbot.py index 837bc66..9302532 100644 --- a/wxbot.py +++ b/wxbot.py @@ -10,13 +10,16 @@ import mimetypes import json import xml.dom.minidom -import urllib +try: + from urllib import urlencode # py2.7 +except: + from urllib.parse import urlencode # py3.x import time import re import random from traceback import format_exc from requests.exceptions import ConnectionError, ReadTimeout -import HTMLParser +from html.parser import HTMLParser UNKONWN = 'unkonwn' SUCCESS = '200' @@ -54,7 +57,7 @@ def request(self, method, url, params=None, data=None, headers=None, cookies=Non timeout, allow_redirects, proxies, hooks, stream, verify, cert, json) except Exception as e: - print e.message, traceback.format_exc() + print(e.message, traceback.format_exc()) continue #重试3次以后再加一次,抛出异常 @@ -145,7 +148,10 @@ def to_unicode(string, encoding='utf-8'): :return: 转换后的Unicode字符串 """ if isinstance(string, str): - return string.decode(encoding) + if sys.version_info[0] == 3: + return string # py3.x + else: + return string.decode(encoding) # py2.7 elif isinstance(string, unicode): return string else: @@ -167,7 +173,7 @@ def get_contact(self): dic_list.append(dic) while int(dic["Seq"]) != 0: - print "[INFO] Geting contacts. Get %s contacts for now" % dic["MemberCount"] + 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) @@ -249,7 +255,7 @@ def get_big_contact(self): self.cursor += self.batch_count cur_batch = map(map_username_batch, cur_batch) user_info_list += self.batch_get_contact(cur_batch) - print "[INFO] Get batch contacts" + print("[INFO] Get batch contacts") self.member_list = user_info_list special_users = ['newsapp', 'filehelper', 'weibo', 'qqmail', @@ -311,8 +317,8 @@ def get_big_contact(self): 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)) - print '[INFO] Get %d contacts' % len(self.contact_list) - print '[INFO] Start to process messages .' + print('[INFO] Get %d contacts' % len(self.contact_list)) + print('[INFO] Start to process messages .') return True @@ -328,7 +334,7 @@ def batch_get_contact(self, cur_batch): r = self.session.post(url, data=json.dumps(params)) r.encoding = 'utf-8' dic = json.loads(r.text) - #print dic['ContactList'] + #print(dic['ContactList']) return dic['ContactList'] @@ -530,7 +536,7 @@ def extract_msg_content(self, msg_type_id, msg): :return: 解析的消息 """ mtype = msg['MsgType'] - content = HTMLParser.HTMLParser().unescape(msg['Content']) + content = HTMLParser().unescape(msg['Content']) msg_id = msg['MsgId'] msg_content = {} @@ -565,7 +571,7 @@ def extract_msg_content(self, msg_type_id, msg): msg_content['data'] = pos msg_content['detail'] = data if self.DEBUG: - print ' %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 @@ -580,28 +586,34 @@ def extract_msg_content(self, msg_type_id, msg): msg_content['data'] = content if self.DEBUG: try: - print ' %s[Text] %s' % (msg_prefix, msg_content['data']) + print(' %s[Text] %s' % (msg_prefix, msg_content['data'])) except UnicodeEncodeError: - print ' %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 sys.version_info[0] == 3: + msg_content['img'] = self.session.get(msg_content['data']).content + else: + msg_content['img'] = self.session.get(msg_content['data']).content.encode('hex') if self.DEBUG: image = self.get_msg_img(msg_id) - print ' %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 sys.version_info[0] == 3: + msg_content['voice'] = self.session.get(msg_content['data']).content + else: + msg_content['voice'] = self.session.get(msg_content['data']).content.encode('hex') if self.DEBUG: voice = self.get_voice(msg_id) - print ' %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: - print ' %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'] @@ -611,18 +623,18 @@ def extract_msg_content(self, msg_type_id, msg): 'city': info['City'], 'gender': ['unknown', 'male', 'female'][info['Sex']]} if self.DEBUG: - 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 ' -----------------------------' + 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: - print ' %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: @@ -641,45 +653,45 @@ def extract_msg_content(self, msg_type_id, msg): 'content': msg.get('Content') # 有的公众号会发一次性3 4条链接一个大图,如果只url那只能获取第一条,content里面有所有的链接 } if self.DEBUG: - 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 ' --------------------------' + 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: - print ' %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: - print ' %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: - print ' %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: - print ' [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']) + print(' %s[video] %s' % (msg_prefix, msg_content['data'])) else: msg_content['type'] = 99 msg_content['data'] = content if self.DEBUG: - print ' %s[Unknown]' % msg_prefix + print(' %s[Unknown]' % msg_prefix) return msg_content def handle_msg(self, r): @@ -709,7 +721,7 @@ def handle_msg(self, r): f.write(msg['StatusNotifyUserName']) with open(os.path.join(self.temp_pwd,'wxid.txt'), 'w') as f: f.write(json.dumps(self.wxid_list)) - print "[INFO] Contact list is too big. Now start to fetch member list ." + print("[INFO] Contact list is too big. Now start to fetch member list .") #self.get_big_contact() elif msg['MsgType'] == 37: # friend request @@ -718,11 +730,11 @@ def handle_msg(self, r): # content = msg['Content'] # username = content[content.index('fromusername='): content.index('encryptusername')] # username = username[username.index('"') + 1: username.rindex('"')] - # print u'[Friend Request]' - # print u' Nickname:' + msg['RecommendInfo']['NickName'] - # print u' 附加消息:'+msg['RecommendInfo']['Content'] - # # print u'Ticket:'+msg['RecommendInfo']['Ticket'] # Ticket添加好友时要用 - # print u' 微信号:'+username #未设置微信号的 腾讯会自动生成一段微信ID 但是无法通过搜索 搜索到此人 + # print(u'[Friend Request]') + # print(u' Nickname:' + msg['RecommendInfo']['NickName']) + # print(u' 附加消息:'+msg['RecommendInfo']['Content']) + # # print(u'Ticket:'+msg['RecommendInfo']['Ticket'] # )Ticket添加好友时要用 + # print(u' 微信号:'+username #未设置微信号的 )腾讯会自动生成一段微信ID 但是无法通过搜索 搜索到此人 elif msg['FromUserName'] == self.my_account['UserName']: # Self msg_type_id = 1 user['name'] = 'self' @@ -746,10 +758,10 @@ def handle_msg(self, r): user['name'] = 'unknown' if not user['name']: user['name'] = 'unknown' - user['name'] = HTMLParser.HTMLParser().unescape(user['name']) + user['name'] = HTMLParser().unescape(user['name']) if self.DEBUG and msg_type_id != 0: - print 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'], @@ -774,7 +786,7 @@ def proc_msg(self): check_time = time.time() try: [retcode, selector] = self.sync_check() - # print '[DEBUG] sync_check:', retcode, selector + # print('[DEBUG] sync_check:', retcode, selector) if retcode == '1100': # 从微信客户端上登出 break elif retcode == '1101': # 从其它设备上登了网页微信 @@ -803,17 +815,17 @@ def proc_msg(self): elif selector == '0': # 无事件 pass else: - print '[DEBUG] sync_check:', retcode, selector + print('[DEBUG] sync_check:', retcode, selector) r = self.sync() if r is not None: self.handle_msg(r) else: - print '[DEBUG] sync_check:', retcode, selector + print('[DEBUG] sync_check:', retcode, selector) time.sleep(10) self.schedule() except: - print '[ERROR] Except in proc_msg' - print 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) @@ -893,7 +905,7 @@ def add_friend_to_group(self,uid,group_name): return False #获取群成员数量并判断邀请方式 group_num=len(self.group_members[gid]) - print '[DEBUG] group_name:%s group_num:%s' % (group_name,group_num) + 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: @@ -1024,7 +1036,7 @@ def send_msg_by_uid(self, word, dst='filehelper'): def upload_media(self, fpath, is_img=False): if not os.path.exists(fpath): - print '[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' @@ -1056,11 +1068,11 @@ def upload_media(self, fpath, is_img=False): # 当file返回值不为0时则为上传失败,尝试第二服务器上传 r = self.session.post(url_2, files=files) if json.loads(r.text)['BaseResponse']['Ret'] != 0: - print '[ERROR] Upload media failure.' + print('[ERROR] Upload media failure.') return None mid = json.loads(r.text)['MediaId'] return mid - except Exception,e: + except Exception as e: return None def send_file_msg_by_uid(self, fpath, uid): @@ -1085,7 +1097,7 @@ def send_file_msg_by_uid(self, fpath, uid): return True else: return False - except Exception,e: + except Exception as e: return False def send_img_msg_by_uid(self, fpath, uid): @@ -1113,7 +1125,7 @@ def send_img_msg_by_uid(self, fpath, uid): return True else: return False - except Exception,e: + except Exception as e: return False def get_user_id(self, name): @@ -1145,7 +1157,7 @@ def send_msg(self, name, word, isfile=False): result = True for line in f.readlines(): line = line.replace('\n', '') - print '-> ' + name + ': ' + line + print('-> ' + name + ': ' + line) if self.send_msg_by_uid(line, uid): pass else: @@ -1160,7 +1172,7 @@ def send_msg(self, name, word, isfile=False): return False else: if self.DEBUG: - print '[ERROR] This user does not exist .' + print('[ERROR] This user does not exist .') return True @staticmethod @@ -1179,35 +1191,35 @@ def run(self): 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 .' + 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,) + print('[ERROR] Web WeChat login failed. failed code=%s' % (result,)) self.status = 'loginout' return if self.login(): - print '[INFO] Web WeChat login succeed .' + print('[INFO] Web WeChat login succeed .') else: - print '[ERROR] Web WeChat login failed .' + print('[ERROR] Web WeChat login failed .') self.status = 'loginout' return if self.init(): - print '[INFO] Web WeChat init succeed .' + print('[INFO] Web WeChat init succeed .') else: - print '[INFO] Web WeChat init failed' + 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 .' + 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) + except Exception as e: + print('[ERROR] Web WeChat run failed --> %s'%(e)) self.status = 'loginout' @@ -1271,7 +1283,7 @@ def wait4login(self): url = LOGIN_TEMPLATE % (tip, self.uuid, int(time.time())) code, data = self.do_request(url) if code == SCANED: - print '[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) @@ -1282,14 +1294,13 @@ def wait4login(self): self.base_host = temp_host[:temp_host.find("/")] return code elif code == TIMEOUT: - print '[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: - print ('[ERROR] WeChat login exception return_code=%s. retry in %s secs later...' % - (code, try_later_secs)) + print(('[ERROR] WeChat login exception return_code=%s. retry in %s secs later...' % (code, try_later_secs))) tip = 1 retry_time -= 1 time.sleep(try_later_secs) @@ -1298,7 +1309,7 @@ def wait4login(self): def login(self): if len(self.redirect_uri) < 4: - print '[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' @@ -1377,7 +1388,7 @@ def sync_check(self): 'synckey': self.sync_key_str, '_': int(time.time()), } - url = 'https://' + self.sync_host + '/cgi-bin/mmwebwx-bin/synccheck?' + urllib.urlencode(params) + url = 'https://' + self.sync_host + '/cgi-bin/mmwebwx-bin/synccheck?' + urlencode(params) try: r = self.session.get(url, timeout=60) r.encoding = 'utf-8'