From 52699bbd017ffd8a1fa8117e0da2e013978ff7bb Mon Sep 17 00:00:00 2001 From: Haskely Date: Mon, 20 Feb 2017 23:52:03 +0800 Subject: [PATCH 1/2] Python-3 transfer to Python-3 --- weixin.py | 168 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 86 insertions(+), 82 deletions(-) diff --git a/weixin.py b/weixin.py index 0271547..f4cc353 100755 --- a/weixin.py +++ b/weixin.py @@ -1,9 +1,9 @@ #!/usr/bin/env python # coding: utf-8 import qrcode -import urllib -import urllib2 -import cookielib +import urllib.request, urllib.parse, urllib.error +import urllib.request, urllib.error, urllib.parse +import http.cookiejar import requests import xml.dom.minidom import json @@ -16,9 +16,9 @@ import random import multiprocessing import platform import logging -import httplib +import http.client from collections import defaultdict -from urlparse import urlparse +from urllib.parse import urlparse from lxml import html #import pdb @@ -32,7 +32,7 @@ def catchKeyboardInterrupt(fn): try: return fn(*args) except KeyboardInterrupt: - print '\n[*] 强制退出程序' + print('\n[*] 强制退出程序') logging.debug('[*] 强制退出程序') return wrapper @@ -40,7 +40,7 @@ def catchKeyboardInterrupt(fn): def _decode_list(data): rv = [] for item in data: - if isinstance(item, unicode): + if isinstance(item, str): item = item.encode('utf-8') elif isinstance(item, list): item = _decode_list(item) @@ -52,10 +52,10 @@ def _decode_list(data): def _decode_dict(data): rv = {} - for key, value in data.iteritems(): - if isinstance(key, unicode): + for key, value in data.items(): + if isinstance(key, str): key = key.encode('utf-8') - if isinstance(value, unicode): + if isinstance(value, str): value = value.encode('utf-8') elif isinstance(value, list): value = _decode_list(value) @@ -118,10 +118,10 @@ class WebWeixin(object): self.TimeOut = 20 # 同步最短时间间隔(单位:秒) self.media_count = -1 - self.cookie = cookielib.CookieJar() - opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookie)) + self.cookie = http.cookiejar.CookieJar() + opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(self.cookie)) opener.addheaders = [('User-agent', self.user_agent)] - urllib2.install_opener(opener) + urllib.request.install_opener(opener) def loadConfig(self, config): if config['DEBUG']: @@ -281,7 +281,7 @@ class WebWeixin(object): PublicUsersList = self.PublicUsersList[:] SpecialUsersList = self.SpecialUsersList[:] - for i in xrange(len(ContactList) - 1, -1, -1): + for i in range(len(ContactList) - 1, -1, -1): Contact = ContactList[i] if Contact['VerifyFlag'] & 8 != 0: # 公众号/服务号 ContactList.remove(Contact) @@ -316,7 +316,7 @@ class WebWeixin(object): ContactCount = dic['Count'] self.GroupList = ContactList - for i in xrange(len(ContactList) - 1, -1, -1): + for i in range(len(ContactList) - 1, -1, -1): Contact = ContactList[i] MemberList = Contact['MemberList'] for member in MemberList: @@ -368,7 +368,7 @@ class WebWeixin(object): '_': int(time.time()), } url = 'https://' + self.syncHost + \ - '/cgi-bin/mmwebwx-bin/synccheck?' + urllib.urlencode(params) + '/cgi-bin/mmwebwx-bin/synccheck?' + urllib.parse.urlencode(params) data = self._get(url) if data == '': return [-1,-1] @@ -391,7 +391,7 @@ class WebWeixin(object): if dic == '': return None if self.DEBUG: - print json.dumps(dic, indent=4) + print(json.dumps(dic, indent=4)) (json.dumps(dic, indent=4)) if dic['BaseResponse']['Ret'] == 0: @@ -539,7 +539,7 @@ class WebWeixin(object): r = requests.post(url, data=data, headers=headers) dic = r.json() if self.DEBUG: - print json.dumps(dic, indent=4) + print(json.dumps(dic, indent=4)) logging.debug(json.dumps(dic, indent=4)) return dic['BaseResponse']['Ret'] == 0 @@ -722,28 +722,28 @@ class WebWeixin(object): msg['message'] = content # 指定了消息内容 - if 'message' in msg.keys(): + if 'message' in list(msg.keys()): content = msg['message'] if groupName != None: - print '%s |%s| %s -> %s: %s' % (message_id, groupName.strip(), srcName.strip(), dstName.strip(), content.replace('
', '\n')) + print('%s |%s| %s -> %s: %s' % (message_id, groupName.strip(), srcName.strip(), dstName.strip(), content.replace('
', '\n'))) logging.info('%s |%s| %s -> %s: %s' % (message_id, groupName.strip(), srcName.strip(), dstName.strip(), content.replace('
', '\n'))) else: - print '%s %s -> %s: %s' % (message_id, srcName.strip(), dstName.strip(), content.replace('
', '\n')) + print('%s %s -> %s: %s' % (message_id, srcName.strip(), dstName.strip(), content.replace('
', '\n'))) logging.info('%s %s -> %s: %s' % (message_id, srcName.strip(), dstName.strip(), content.replace('
', '\n'))) def handleMsg(self, r): for msg in r['AddMsgList']: - print '[*] 你有新的消息,请注意查收' + print('[*] 你有新的消息,请注意查收') logging.debug('[*] 你有新的消息,请注意查收') if self.DEBUG: fn = 'msg' + str(int(random.random() * 1000)) + '.json' with open(fn, 'w') as f: f.write(json.dumps(msg)) - print '[*] 该消息已储存到文件: ' + fn + print('[*] 该消息已储存到文件: ' + fn) logging.debug('[*] 该消息已储存到文件: %s' % (fn)) msgType = msg['MsgType'] @@ -754,13 +754,17 @@ class WebWeixin(object): if msgType == 1: raw_msg = {'raw_msg': msg} self._showMsg(raw_msg) +#自己加的代码-------------------------------------------# + #if self.autoReplyRevokeMode: + # store +#自己加的代码-------------------------------------------# if self.autoReplyMode: ans = self._xiaodoubi(content) + '\n[微信机器人自动回复]' if self.webwxsendmsg(ans, msg['FromUserName']): - print '自动回复: ' + ans + print('自动回复: ' + ans) logging.info('自动回复: ' + ans) else: - print '自动回复失败' + print('自动回复失败') logging.info('自动回复失败') elif msgType == 3: image = self.webwxgetmsgimg(msgid) @@ -776,13 +780,13 @@ class WebWeixin(object): self._safe_open(voice) elif msgType == 42: info = msg['RecommendInfo'] - print '%s 发送了一张名片:' % name - print '=========================' - print '= 昵称: %s' % info['NickName'] - print '= 微信号: %s' % info['Alias'] - print '= 地区: %s %s' % (info['Province'], info['City']) - print '= 性别: %s' % ['未知', '男', '女'][info['Sex']] - print '=========================' + print('%s 发送了一张名片:' % name) + print('=========================') + print('= 昵称: %s' % info['NickName']) + print('= 微信号: %s' % info['Alias']) + print('= 地区: %s %s' % (info['Province'], info['City'])) + print('= 性别: %s' % ['未知', '男', '女'][info['Sex']]) + print('=========================') raw_msg = {'raw_msg': msg, 'message': '%s 发送了一张名片: %s' % ( name.strip(), json.dumps(info))} self._showMsg(raw_msg) @@ -795,13 +799,13 @@ class WebWeixin(object): elif msgType == 49: appMsgType = defaultdict(lambda: "") appMsgType.update({5: '链接', 3: '音乐', 7: '微博'}) - print '%s 分享了一个%s:' % (name, appMsgType[msg['AppMsgType']]) - print '=========================' - print '= 标题: %s' % msg['FileName'] - print '= 描述: %s' % self._searchContent('des', content, 'xml') - print '= 链接: %s' % msg['Url'] - print '= 来自: %s' % self._searchContent('appname', content, 'xml') - print '=========================' + print('%s 分享了一个%s:' % (name, appMsgType[msg['AppMsgType']])) + print('=========================') + print('= 标题: %s' % msg['FileName']) + print('= 描述: %s' % self._searchContent('des', content, 'xml')) + print('= 链接: %s' % msg['Url']) + print('= 来自: %s' % self._searchContent('appname', content, 'xml')) + print('=========================') card = { 'title': msg['FileName'], 'description': self._searchContent('des', content, 'xml'), @@ -831,7 +835,7 @@ class WebWeixin(object): self._showMsg(raw_msg) def listenMsgMode(self): - print '[*] 进入消息监听模式 ... 成功' + print('[*] 进入消息监听模式 ... 成功') logging.debug('[*] 进入消息监听模式 ... 成功') self._run('[*] 进行同步线路测试 ... ', self.testsynccheck) playWeChat = 0 @@ -840,14 +844,14 @@ class WebWeixin(object): self.lastCheckTs = time.time() [retcode, selector] = self.synccheck() if self.DEBUG: - print 'retcode: %s, selector: %s' % (retcode, selector) + print('retcode: %s, selector: %s' % (retcode, selector)) logging.debug('retcode: %s, selector: %s' % (retcode, selector)) if retcode == '1100': - print '[*] 你在手机上登出了微信,债见' + print('[*] 你在手机上登出了微信,债见') logging.debug('[*] 你在手机上登出了微信,债见') break if retcode == '1101': - print '[*] 你在其他地方登录了 WEB 版微信,债见' + print('[*] 你在其他地方登录了 WEB 版微信,债见') logging.debug('[*] 你在其他地方登录了 WEB 版微信,债见') break elif retcode == '0': @@ -858,11 +862,11 @@ class WebWeixin(object): elif selector == '6': # TODO redEnvelope += 1 - print '[*] 收到疑似红包消息 %d 次' % redEnvelope + print('[*] 收到疑似红包消息 %d 次' % redEnvelope) logging.debug('[*] 收到疑似红包消息 %d 次' % redEnvelope) elif selector == '7': playWeChat += 1 - print '[*] 你在手机上玩微信被我发现了 %d 次' % playWeChat + print('[*] 你在手机上玩微信被我发现了 %d 次' % playWeChat) logging.debug('[*] 你在手机上玩微信被我发现了 %d 次' % playWeChat) r = self.webwxsync() elif selector == '0': @@ -879,19 +883,19 @@ class WebWeixin(object): line = line.replace('\n', '') self._echo('-> ' + name + ': ' + line) if self.webwxsendmsg(line, id): - print ' [成功]' + print(' [成功]') else: - print ' [失败]' + print(' [失败]') time.sleep(1) else: if self.webwxsendmsg(word, id): - print '[*] 消息发送成功' + print('[*] 消息发送成功') logging.debug('[*] 消息发送成功') else: - print '[*] 消息发送失败' + print('[*] 消息发送失败') logging.debug('[*] 消息发送失败') else: - print '[*] 此用户不存在' + print('[*] 此用户不存在') logging.debug('[*] 此用户不存在') def sendMsgToAll(self, word): @@ -901,9 +905,9 @@ class WebWeixin(object): id = contact['UserName'] self._echo('-> ' + name + ': ' + word) if self.webwxsendmsg(word, id): - print ' [成功]' + print(' [成功]') else: - print ' [失败]' + print(' [失败]') time.sleep(1) def sendImg(self, name, file_name): @@ -925,18 +929,18 @@ class WebWeixin(object): @catchKeyboardInterrupt def start(self): self._echo('[*] 微信网页版 ... 开动') - print + print() logging.debug('[*] 微信网页版 ... 开动') while True: self._run('[*] 正在获取 uuid ... ', self.getUUID) self._echo('[*] 正在获取二维码 ... 成功') - print + print() logging.debug('[*] 微信网页版 ... 开动') self.genQRCode() - print '[*] 请使用微信扫描二维码以登录 ... ' + print('[*] 请使用微信扫描二维码以登录 ... ') if not self.waitForLogin(): continue - print '[*] 请在手机上点击确认以登录 ... ' + print('[*] 请在手机上点击确认以登录 ... ') if not self.waitForLogin(0): continue break @@ -947,33 +951,33 @@ class WebWeixin(object): self._run('[*] 获取联系人 ... ', self.webwxgetcontact) self._echo('[*] 应有 %s 个联系人,读取到联系人 %d 个' % (self.MemberCount, len(self.MemberList))) - print + print() self._echo('[*] 共有 %d 个群 | %d 个直接联系人 | %d 个特殊账号 | %d 公众号或服务号' % (len(self.GroupList), len(self.ContactList), len(self.SpecialUsersList), len(self.PublicUsersList))) - print + print() self._run('[*] 获取群 ... ', self.webwxbatchgetcontact) logging.debug('[*] 微信网页版 ... 开动') if self.DEBUG: - print self + print(self) logging.debug(self) - if self.interactive and raw_input('[*] 是否开启自动回复模式(y/n): ') == 'y': + if self.interactive and input('[*] 是否开启自动回复模式(y/n): ') == 'y': self.autoReplyMode = True - print '[*] 自动回复模式 ... 开启' + print('[*] 自动回复模式 ... 开启') logging.debug('[*] 自动回复模式 ... 开启') else: - print '[*] 自动回复模式 ... 关闭' + print('[*] 自动回复模式 ... 关闭') logging.debug('[*] 自动回复模式 ... 关闭') if sys.platform.startswith('win'): - import thread - thread.start_new_thread(self.listenMsgMode()) + import _thread + _thread.start_new_thread(self.listenMsgMode()) else: listenProcess = multiprocessing.Process(target=self.listenMsgMode) listenProcess.start() while True: - text = raw_input('') + text = input('') if text == 'quit': listenProcess.terminate() print('[*] 退出微信') @@ -989,15 +993,15 @@ class WebWeixin(object): [name, file] = text[3:].split(':') self.sendMsg(name, file, True) elif text[:3] == 'f->': - print '发送文件' + print('发送文件') logging.debug('发送文件') elif text[:3] == 'i->': - print '发送图片' + print('发送图片') [name, file_name] = text[3:].split(':') self.sendImg(name, file_name) logging.debug('发送图片') elif text[:3] == 'e->': - print '发送表情' + print('发送表情') [name, file_name] = text[3:].split(':') self.sendEmotion(name, file_name) logging.debug('发送表情') @@ -1012,7 +1016,7 @@ class WebWeixin(object): def _run(self, str, func, *args): self._echo(str) if func(*args): - print '成功' + print('成功') logging.debug('%s... 成功' % (str)) else: print('失败\n[*] 退出程序') @@ -1028,7 +1032,7 @@ class WebWeixin(object): for i in mat: BLACK = '\033[40m \033[0m' WHITE = '\033[47m \033[0m' - print ''.join([BLACK if j else WHITE for j in i]) + print(''.join([BLACK if j else WHITE for j in i])) def _str2qr(self, str): print(str) @@ -1046,29 +1050,29 @@ class WebWeixin(object): if not data: return data result = None - if type(data) == unicode: + if type(data) == str: result = data elif type(data) == str: result = data.decode('utf-8') return result def _get(self, url, api=None): - request = urllib2.Request(url=url) + request = urllib.request.Request(url=url) request.add_header('Referer', 'https://wx.qq.com/') if api == 'webwxgetvoice': request.add_header('Range', 'bytes=0-') if api == 'webwxgetvideo': request.add_header('Range', 'bytes=0-') try: - response = urllib2.urlopen(request) + response = urllib.request.urlopen(request) data = response.read() logging.debug(url) return data - except urllib2.HTTPError, e: + except urllib.error.HTTPError as e: logging.error('HTTPError = ' + str(e.code)) - except urllib2.URLError, e: + except urllib.error.URLError as e: logging.error('URLError = ' + str(e.reason)) - except httplib.HTTPException, e: + except http.client.HTTPException as e: logging.error('HTTPException') except Exception: import traceback @@ -1077,24 +1081,24 @@ class WebWeixin(object): def _post(self, url, params, jsonfmt=True): if jsonfmt: - request = urllib2.Request(url=url, data=json.dumps(params)) + request = urllib.request.Request(url=url, data=json.dumps(params)) request.add_header( 'ContentType', 'application/json; charset=UTF-8') else: - request = urllib2.Request(url=url, data=urllib.urlencode(params)) + request = urllib.request.Request(url=url, data=urllib.parse.urlencode(params)) try: - response = urllib2.urlopen(request) + response = urllib.request.urlopen(request) data = response.read() if jsonfmt: return json.loads(data, object_hook=_decode_dict) return data - except urllib2.HTTPError, e: + except urllib.error.HTTPError as e: logging.error('HTTPError = ' + str(e.code)) - except urllib2.URLError, e: + except urllib.error.URLError as e: logging.error('URLError = ' + str(e.reason)) - except httplib.HTTPException, e: + except http.client.HTTPException as e: logging.error('HTTPException') except Exception: import traceback From 03db42d4352b0bbc14f952f721398f4270e51a11 Mon Sep 17 00:00:00 2001 From: Haskely Date: Tue, 21 Feb 2017 03:07:56 +0800 Subject: [PATCH 2/2] Transfer it to Python3 manually MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Really tedious! --- saved/qrcodes/qrcode.jpg | Bin 0 -> 42241 bytes weixin.py | 108 +++++++++++++++++++++------------------ 2 files changed, 59 insertions(+), 49 deletions(-) create mode 100644 saved/qrcodes/qrcode.jpg diff --git a/saved/qrcodes/qrcode.jpg b/saved/qrcodes/qrcode.jpg new file mode 100644 index 0000000000000000000000000000000000000000..862fd9d23fa8900d39ae622571bbc2998100a284 GIT binary patch literal 42241 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 D(IFG7 literal 0 HcmV?d00001 diff --git a/weixin.py b/weixin.py index f4cc353..2ed25d9 100755 --- a/weixin.py +++ b/weixin.py @@ -143,7 +143,10 @@ class WebWeixin(object): 'lang': self.lang, '_': int(time.time()), } - data = self._post(url, params, False) + #r = requests.get(url=url, params=params) + #r.encoding = 'utf-8' + #data = r.text + data = self._post(url, params, False).decode("utf-8") if data == '': return False regx = r'window.QRLogin.code = (\d+); window.QRLogin.uuid = "(\S+?)"' @@ -163,7 +166,7 @@ class WebWeixin(object): else: self._str2qr('https://login.weixin.qq.com/l/' + self.uuid) - def _showQRCodeImg(self, os): + def _showQRCodeImg(self, str): url = 'https://login.weixin.qq.com/qrcode/' + self.uuid params = { 't': 'webwx', @@ -174,9 +177,9 @@ class WebWeixin(object): if data == '': return QRCODE_PATH = self._saveFile('qrcode.jpg', data, '_showQRCodeImg') - if os == 'win': + if str == 'win': os.startfile(QRCODE_PATH) - elif os == 'macos': + elif str == 'macos': subprocess.call(["open", QRCODE_PATH]) else: return @@ -188,7 +191,7 @@ class WebWeixin(object): data = self._get(url) if data == '': return False - pm = re.search(r'window.code=(\d+);', data) + pm = re.search(r"window.code=(\d+);", data) code = pm.group(1) if code == '201': @@ -242,13 +245,13 @@ class WebWeixin(object): dic = self._post(url, params) if dic == '': return False - self.SyncKey = dic['SyncKey'] - self.User = dic['User'] + self.SyncKey = dic[b'SyncKey'] + self.User = dic[b'User'] # synckey for synccheck self.synckey = '|'.join( - [str(keyVal['Key']) + '_' + str(keyVal['Val']) for keyVal in self.SyncKey['List']]) + [str(keyVal[b'Key']) + '_' + str(keyVal[b'Val']) for keyVal in self.SyncKey[b'List']]) - return dic['BaseResponse']['Ret'] == 0 + return dic[b'BaseResponse'][b'Ret'] == 0 def webwxstatusnotify(self): url = self.base_uri + \ @@ -256,15 +259,15 @@ class WebWeixin(object): params = { 'BaseRequest': self.BaseRequest, "Code": 3, - "FromUserName": self.User['UserName'], - "ToUserName": self.User['UserName'], + "FromUserName": self.User[b'UserName'].decode(), + "ToUserName": self.User[b'UserName'].decode(), "ClientMsgId": int(time.time()) } dic = self._post(url, params) if dic == '': return False - return dic['BaseResponse']['Ret'] == 0 + return dic[b'BaseResponse'][b'Ret'] == 0 def webwxgetcontact(self): SpecialUsers = self.SpecialUsers @@ -274,8 +277,8 @@ class WebWeixin(object): if dic == '': return False - self.MemberCount = dic['MemberCount'] - self.MemberList = dic['MemberList'] + self.MemberCount = dic[b'MemberCount'] + self.MemberList = dic[b'MemberList'] ContactList = self.MemberList[:] GroupList = self.GroupList[:] PublicUsersList = self.PublicUsersList[:] @@ -283,16 +286,16 @@ class WebWeixin(object): for i in range(len(ContactList) - 1, -1, -1): Contact = ContactList[i] - if Contact['VerifyFlag'] & 8 != 0: # 公众号/服务号 + if Contact[b'VerifyFlag'] & 8 != 0: # 公众号/服务号 ContactList.remove(Contact) self.PublicUsersList.append(Contact) - elif Contact['UserName'] in SpecialUsers: # 特殊账号 + elif Contact[b'UserName'].decode() in SpecialUsers: # 特殊账号 ContactList.remove(Contact) self.SpecialUsersList.append(Contact) - elif '@@' in Contact['UserName']: # 群聊 + elif '@@' in Contact[b'UserName'].decode(): # 群聊 ContactList.remove(Contact) self.GroupList.append(Contact) - elif Contact['UserName'] == self.User['UserName']: # 自己 + elif Contact[b'UserName'] == self.User[b'UserName']: # 自己 ContactList.remove(Contact) self.ContactList = ContactList @@ -302,23 +305,28 @@ class WebWeixin(object): url = self.base_uri + \ '/webwxbatchgetcontact?type=ex&r=%s&pass_ticket=%s' % ( int(time.time()), self.pass_ticket) + List=[{"UserName": g[b'UserName'], "EncryChatRoomId":""} for g in self.GroupList] + for x in List: + x['UserName']=x['UserName'].decode() + + print(1) params = { 'BaseRequest': self.BaseRequest, "Count": len(self.GroupList), - "List": [{"UserName": g['UserName'], "EncryChatRoomId":""} for g in self.GroupList] + "List": List } dic = self._post(url, params) if dic == '': return False # blabla ... - ContactList = dic['ContactList'] - ContactCount = dic['Count'] + ContactList = dic[b'ContactList'] + ContactCount = dic[b'Count'] self.GroupList = ContactList for i in range(len(ContactList) - 1, -1, -1): Contact = ContactList[i] - MemberList = Contact['MemberList'] + MemberList = Contact[b'MemberList'] for member in MemberList: self.GroupMemeberList.append(member) return True @@ -337,18 +345,18 @@ class WebWeixin(object): return None # blabla ... - return dic['ContactList'] + return dic[b'ContactList'].decode() def testsynccheck(self): SyncHost = [ 'webpush.weixin.qq.com', - #'webpush2.weixin.qq.com', + 'webpush2.weixin.qq.com', 'webpush.wechat.com', 'webpush1.wechat.com', 'webpush2.wechat.com', 'webpush.wx.qq.com', 'webpush2.wx.qq.com' - # 'webpush.wechatapp.com' + 'webpush.wechatapp.com' ] for host in SyncHost: self.syncHost = host @@ -367,11 +375,11 @@ class WebWeixin(object): 'synckey': self.synckey, '_': int(time.time()), } - url = 'https://' + self.syncHost + \ - '/cgi-bin/mmwebwx-bin/synccheck?' + urllib.parse.urlencode(params) + url = 'https://' + self.syncHost + '/cgi-bin/mmwebwx-bin/synccheck?' + urllib.parse.urlencode(params) data = self._get(url) if data == '': return [-1,-1] + pm = re.search( r'window.synccheck={retcode:"(\d+)",selector:"(\d+)"}', data) retcode = pm.group(1) @@ -394,8 +402,8 @@ class WebWeixin(object): print(json.dumps(dic, indent=4)) (json.dumps(dic, indent=4)) - if dic['BaseResponse']['Ret'] == 0: - self.SyncKey = dic['SyncKey'] + if dic[b'BaseResponse'][b'Ret'] == 0: + self.SyncKey = dic[b'SyncKey'].decode() self.synckey = '|'.join( [str(keyVal['Key']) + '_' + str(keyVal['Val']) for keyVal in self.SyncKey['List']]) return dic @@ -420,7 +428,7 @@ class WebWeixin(object): data = json.dumps(params, ensure_ascii=False).encode('utf8') r = requests.post(url, data=data, headers=headers) dic = r.json() - return dic['BaseResponse']['Ret'] == 0 + return dic[b'BaseResponse'][b'Ret'] == 0 def webwxuploadmedia(self, image_name): url = 'https://file2.wx.qq.com/cgi-bin/mmwebwx-bin/webwxuploadmedia?f=json' @@ -516,7 +524,7 @@ class WebWeixin(object): data = json.dumps(data_json, ensure_ascii=False).encode('utf8') r = requests.post(url, data=data, headers=headers) dic = r.json() - return dic['BaseResponse']['Ret'] == 0 + return dic[b'BaseResponse'][b'Ret'] == 0 def webwxsendmsgemotion(self, user_id, media_id): url = 'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendemoticon?fun=sys&f=json&pass_ticket=%s' % self.pass_ticket @@ -541,7 +549,7 @@ class WebWeixin(object): if self.DEBUG: print(json.dumps(dic, indent=4)) logging.debug(json.dumps(dic, indent=4)) - return dic['BaseResponse']['Ret'] == 0 + return dic[b'BaseResponse'][b'Ret'] == 0 def _saveFile(self, filename, data, api=None): fn = filename @@ -642,14 +650,14 @@ class WebWeixin(object): # 直接联系人 for member in self.ContactList: - if member['UserName'] == id: - name = member['RemarkName'] if member[ - 'RemarkName'] else member['NickName'] + if member[b'UserName'].decode() == id: + name = member[b'RemarkName'].decode() if member[ + b'RemarkName'].decode() else member[b'NickName'].decode() # 群友 for member in self.GroupMemeberList: - if member['UserName'] == id: - name = member['DisplayName'] if member[ - 'DisplayName'] else member['NickName'] + if member[b'UserName'].decode() == id: + name = member[b'DisplayName'] if member[ + b'DisplayName'].decode() else member[b'NickName'].decode() if name == '未知群' or name == '陌生人': logging.debug(id) @@ -657,8 +665,8 @@ class WebWeixin(object): def getUSerID(self, name): for member in self.MemberList: - if name == member['RemarkName'] or name == member['NickName']: - return member['UserName'] + if name == member[b'RemarkName'].decode() or name == member[b'NickName'].decode(): + return member[b'UserName'].decode() return None def _showMsg(self, message): @@ -900,9 +908,9 @@ class WebWeixin(object): def sendMsgToAll(self, word): for contact in self.ContactList: - name = contact['RemarkName'] if contact[ - 'RemarkName'] else contact['NickName'] - id = contact['UserName'] + name = contact[b'RemarkName'].decode() if contact[ + b'RemarkName'].decode() else contact[b'NickName'].decode() + id = contact[b'UserName'].decode() self._echo('-> ' + name + ': ' + word) if self.webwxsendmsg(word, id): print(' [成功]') @@ -1056,7 +1064,7 @@ class WebWeixin(object): result = data.decode('utf-8') return result - def _get(self, url, api=None): + def _get(self, url: object, api: object = None) -> object: request = urllib.request.Request(url=url) request.add_header('Referer', 'https://wx.qq.com/') if api == 'webwxgetvoice': @@ -1065,7 +1073,7 @@ class WebWeixin(object): request.add_header('Range', 'bytes=0-') try: response = urllib.request.urlopen(request) - data = response.read() + data = response.read().decode('utf-8') logging.debug(url) return data except urllib.error.HTTPError as e: @@ -1079,20 +1087,22 @@ class WebWeixin(object): logging.error('generic exception: ' + traceback.format_exc()) return '' - def _post(self, url, params, jsonfmt=True): + def _post(self, url: object, params: object, jsonfmt: object = True) -> object: if jsonfmt: - request = urllib.request.Request(url=url, data=json.dumps(params)) + data = json.dumps(params) + data=data.encode() + request = urllib.request.Request(url=url, data=data) request.add_header( 'ContentType', 'application/json; charset=UTF-8') else: - request = urllib.request.Request(url=url, data=urllib.parse.urlencode(params)) + request = urllib.request.Request(url=url, data=urllib.parse.urlencode(params).encode(encoding='utf-8')) try: response = urllib.request.urlopen(request) data = response.read() if jsonfmt: - return json.loads(data, object_hook=_decode_dict) + return json.loads(data.decode('utf-8'), object_hook=_decode_dict) return data except urllib.error.HTTPError as e: logging.error('HTTPError = ' + str(e.code))