Created
August 31, 2017 08:16
-
-
Save leeyisoft/fd2a469cbdf17d3501a41cce642b8777 to your computer and use it in GitHub Desktop.
pip3 install -U wxpy \n mkdir pkl
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# encoding: utf-8 | |
import requests | |
import base64 | |
import hashlib | |
import os | |
from wxpy import * | |
from wxpy.api.chats.friend import Friend | |
def _md5(Str): | |
m = hashlib.md5(Str.encode(encoding='utf8')) | |
return m.hexdigest() | |
class WxBot(object): | |
bot = None | |
qr_path = 'qrcode.png' | |
port = '' | |
"""docstring for WxBot""" | |
def __init__(self, port, api_url, security_key): | |
self.port = str(port) | |
self.api_url = str(api_url) | |
self.security_key = str(security_key) | |
self.qr_path = './qrcode/%s_qrcode.png' % self.port | |
self.bot = Bot(cache_path='./pkl/%s.pkl' % self.port | |
, qr_callback=self.qr_callback | |
) | |
self.bot.enable_puid(path='./pkl/%s_puid.pkl' % self.port) | |
# print(dir(self.bot)) | |
def qr_callback(self, **kwargs): | |
qrcode = kwargs.get('qrcode') | |
if not qrcode: | |
return False | |
with open(self.qr_path, 'wb') as fp: | |
fp.write(qrcode) | |
b64img = base64.b64encode(qrcode) #读取文件内容,转换为base64编码 | |
# 下面参数顺序很不能够变 | |
payload = { | |
'data' : 'data:image/png;base64,%s' % bytes.decode(b64img), | |
# 'name': '', | |
'port' : self.port, | |
'qq' : '', | |
'type': 'wechat', | |
} | |
# print("payload", payload) | |
sign = self.security_key | |
for key in payload: | |
sign += '%s=%s' % (str(key), str(payload[key])) | |
payload['sign'] = _md5(sign) | |
response = requests.post(self.api_url, data=payload) | |
# print('response %s' % response.text) | |
def login_callback(self): | |
# 登陆成功记录端口和服务的关系 | |
if os.path.isfile(self.qr_path): | |
# 下面参数顺序很不能够变 | |
payload = { | |
'data' : '', | |
# 'name' : str(self.bot.self.name), | |
'port' : self.port, | |
'qq' : str(self.bot.self.puid), | |
'type': 'wechat', | |
} | |
# print('payload', payload) | |
sign = self.security_key | |
for key in payload: | |
sign += '%s=%s' % (str(key), str(payload[key])) | |
payload['sign'] = _md5(sign) | |
response = requests.post(self.api_url, data=payload) | |
os.remove(self.qr_path) | |
def _list_buddy(self, params): | |
""" | |
查询好友 | |
参数 以是 sex(性别), province(省份), city(城市) 等。例如可指定 province='广东' | |
""" | |
response = {} | |
keywords = params.get('keywords', '') | |
sex = params.get('sex') | |
city = params.get('city') | |
province = params.get('province') | |
sex = sex if sex else False | |
city = city if city else False | |
province = province if province else False | |
if sex and city and province: | |
response = self.bot.friends(update=True).search(keywords | |
, sex=sex | |
, city=city | |
, province=province | |
) | |
elif sex and city: | |
response = self.bot.friends(update=True).search(keywords | |
, sex=sex | |
, city=city | |
) | |
elif sex and province: | |
response = self.bot.friends(update=True).search(keywords | |
, sex=sex | |
, province=province | |
) | |
elif city and province: | |
response = self.bot.friends(update=True).search(keywords | |
, city=city | |
, province=province | |
) | |
else: | |
response = self.bot.friends(update=True).search(keywords) | |
# print('keywords: %s,' % keywords | |
# , 'sex: %s,' % sex | |
# ,'city: %s,' % city | |
# ,'province: %s,' % province | |
# ) | |
def _filter_friend_raw(Friend): | |
# print('raw', type(raw), raw) | |
return { | |
'puid': Friend.puid, | |
'NickName': Friend.raw.get('NickName'), | |
'UserName': Friend.raw.get('UserName'), | |
'RemarkName': Friend.raw.get('RemarkName'), | |
'Sex': Friend.raw.get('Sex'), | |
'Province': Friend.raw.get('Province'), | |
'City': Friend.raw.get('City'), | |
'Signature': Friend.raw.get('Signature'), | |
} | |
data = [ _filter_friend_raw(Friend) for Friend in response] | |
return {'result': data, 'count': len(data)} | |
def _send_buddy(self, params): | |
""" | |
给好友发送消息 | |
""" | |
buddy = params.get('buddy') | |
content = params.get('content') | |
# print('buddy', buddy) | |
# print('content', content) | |
try: | |
f = Friend(buddy, self.bot) | |
res = f.send(content) | |
res = {'result': 'success'} | |
except Exception as e: | |
res = {'err': str(e)} | |
# print('send/buddy', type(res), res) | |
return res | |
def _send_buddy_remarkname(self, params): | |
RemarkName = params.get('RemarkName') | |
content = params.get('content') | |
try: | |
my_friend = self.bot.friends().search(RemarkName) | |
if not my_friend: | |
my_friend = self.bot.friends(update=True).search(RemarkName) | |
if not my_friend: | |
raise Exception('Friend [%s] does not exist' % RemarkName) | |
res = my_friend[0].send(content) | |
res = {'result': 'success'} | |
except Exception as e: | |
res = {'err': str(e)} | |
# print('send/buddy/remarkname', type(res), res) | |
return res | |
def call(self, cmd, params): | |
response = {} | |
try: | |
if cmd=='list/buddy': | |
response = self._list_buddy(params) | |
elif cmd=='send/buddy': | |
response = self._send_buddy(params) | |
elif cmd=='send/buddy/remarkname': | |
response = self._send_buddy_remarkname(params) | |
except Exception as e: | |
response = {'err': str(e), 'links': 'http://wxpy.readthedocs.io/zh/latest/'} | |
raise e | |
return response | |
if __name__ == '__main__': | |
try: | |
PORT = 8110 | |
wechat_bot = WxBot(PORT) | |
wechat_bot.login_callback() | |
# print(wechat_bot.bot.self.puid) | |
# print(dir(wechat_bot.bot.self)) | |
# exit(0) | |
cmd = 'list/buddy' | |
# params = {'keywords':'李', 'sex':2, 'city':'深圳', 'province':'广东'} | |
params = {'keywords':'aaaleeyi茉莉茶'} | |
response = wechat_bot.call(cmd, params) | |
print(type(response), response) | |
cmd = 'send/buddy' | |
# [{'puid': 'f89084da', 'NickName': '茉莉茶', 'UserName': '@e63bbd48c33b4aa35b1eacfd72e0210f25f976f32fa8e5962931313b57fc09c0', 'RemarkName': '', 'Sex': 0, 'Province': '', 'City': '', 'Signature': 'molochakello'}] | |
params = {'buddy':{'UserName': '@7639ff66321d9e8a474fdc9945c9b16ae0ac5a99f554dde77227c63b21861e82'}, 'content': 'eecccc usernme 变化33'} | |
response = wechat_bot.call(cmd, params) | |
print(type(response), response) | |
cmd = 'send/buddy/remarkname' | |
# [{'puid': 'f89084da', 'NickName': '茉莉茶', 'UserName': '@e63bbd48c33b4aa35b1eacfd72e0210f25f976f32fa8e5962931313b57fc09c0', 'RemarkName': '', 'Sex': 0, 'Province': '', 'City': '', 'Signature': 'molochakello'}] | |
params = {'RemarkName':'aaaleeyi茉莉茶', 'content': 'dddd usernme 变化33'} | |
response = wechat_bot.call(cmd, params) | |
print(type(response), response) | |
except KeyboardInterrupt: | |
sys.exit(0) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# encoding: utf-8 | |
import sys | |
import os | |
import logging | |
import socketserver | |
import json | |
from multiprocessing import Pool | |
# https://github.com/serverdensity/python-daemon/blob/master/daemon.py | |
from amqp.daemon import Daemon | |
from common.wxpy_bot import WxBot | |
logger_name = 'wxpy_server' | |
HOST = '127.0.0.1' | |
def _logger_init(logger_name, logger_path, logger_level): | |
""" | |
日志初始化 | |
""" | |
formatter = logging.Formatter('[%(asctime)s]-[%(name)s]-[%(levelname)s]: %(message)s') | |
logger = logging.getLogger(logger_name) | |
logger.setLevel(logger_level) | |
fh = logging.FileHandler(logger_path) | |
fh.setFormatter(formatter) | |
logger.addHandler(fh) | |
class SingleTCPHandler(socketserver.BaseRequestHandler): | |
"One instance per connection. Override handle(self) to customize action." | |
def handle(self): | |
# self.request is the client connection | |
data = self.request.recv(102400) # clip input at 100Kb | |
text = data.decode('utf-8') | |
try: | |
# 把单引号替换成双引号 | |
text = text.replace("'",'"') | |
req_dict = json.loads(text) | |
cmd = req_dict.get('cmd') | |
params = req_dict.get('params', {}) | |
if not cmd: | |
raise Exception('cmd is necessary parameter') | |
response = self.server.wechat_bot.call(cmd, params) | |
response = json.dumps(response) | |
except Exception as e: | |
response = json.dumps({'err': str(e)}) | |
self.request.send(bytes(response, 'utf8')) | |
self.request.close() | |
class WXPYServer(socketserver.ThreadingMixIn, socketserver.TCPServer): | |
# Ctrl-C will cleanly kill all spawned threads | |
daemon_threads = True | |
# much faster rebinding | |
allow_reuse_address = True | |
wechat_bot = None | |
def __init__(self, server_address, RequestHandlerClass): | |
from config import qrcode_upload_api | |
from config import qrcode_upload_key | |
# print('server_address', server_address) | |
_, port = server_address | |
self.wechat_bot = WxBot(port=port | |
, api_url=qrcode_upload_api | |
, security_key=qrcode_upload_key | |
) | |
self.wechat_bot.login_callback() | |
socketserver.TCPServer.__init__(self, server_address, RequestHandlerClass) | |
class WXPYServerDaemon(Daemon): | |
def start_server(self, port): | |
self.log('port', port) | |
try: | |
server = WXPYServer((HOST, port), SingleTCPHandler) | |
server.serve_forever() | |
except Exception as e: | |
self.log(e) | |
raise e | |
def run(self): | |
""" | |
对Pool对象调用join()方法会等待所有子进程执行完毕,调用join()之前必须先调用close(),调用close()之后就不能继续添加新的Process了。 | |
""" | |
# 8110 ~ 8179 之间的端口计划给wxpy用; 8180 ~ 8210 之间的端口计划给qqbot用 | |
from config import wxpy_server_ports | |
pool_num = len(wxpy_server_ports) | |
p = Pool(pool_num) | |
# logging.getLogger(logger_name).info("pid[%s] run consumers: %s" % (os.getpid(), consumers)) | |
for port in wxpy_server_ports: | |
p.apply_async(self.start_server, args=(port,)) | |
p.close() | |
p.join() | |
def restart(self): | |
""" | |
Restart the daemon | |
""" | |
self.stop() | |
self.start() | |
if __name__ == '__main__': | |
if len(sys.argv) != 2: | |
print( "ERROR: Wrong options for wxpy_server.py [start|stop|restart]") | |
sys.exit(1) | |
cmd = sys.argv[1] | |
data_dir = './logs' | |
if not os.path.exists(data_dir): | |
print( "ERROR: pid_idr [%s] not exists!" % data_dir) | |
sys.exit(1) | |
pid_path = os.path.join(data_dir, 'wxpy_server.pid') | |
log_path = os.path.join(data_dir, 'wxpy_server.log') | |
_logger_init(logger_name, log_path, logging.INFO) | |
wxpy_server = WXPYServerDaemon(pid_path, stdout=log_path) | |
if cmd == "start": | |
wxpy_server.start() | |
elif cmd == 'stop': | |
wxpy_server.stop() | |
elif cmd == 'restart': | |
wxpy_server.restart() | |
else: | |
print( "wxpy_server.py [start|stop|restart]") | |
sys.exit(1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment